bitkeeper revision 1.802.1.1 (405853fcN7rcf_nAOUv8-8C-udNDkw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 17 Mar 2004 13:34:52 +0000 (13:34 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 17 Mar 2004 13:34:52 +0000 (13:34 +0000)
vnetif.c, Makefile:
  new file
Many files:
  Relaid out xenolinux drivers. More x86_64 stuff.
domain_page.c:
  Rename: xen/common/domain_page.c -> xen/arch/i386/domain_page.c
vbd.c:
  Rename: xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_vbd.c -> xenolinux-2.4.25-sparse/arch/xeno/drivers/block/vbd.c
block.h:
  Rename: xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.h -> xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.h
block.c:
  Rename: xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.c -> xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.c
core.c:
  Rename: xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c -> xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/core.c
evtchn.c:
  Rename: xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c -> xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/evtchn.c

53 files changed:
.rootkeys
tools/xc/lib/xc_linux_build.c
tools/xc/lib/xc_linux_restore.c
tools/xc/lib/xc_linux_save.c
tools/xc/lib/xc_netbsd_build.c
xen/arch/i386/domain_page.c [new file with mode: 0644]
xen/arch/i386/mm.c
xen/arch/i386/process.c
xen/common/dom0_ops.c
xen/common/domain.c
xen/common/domain_page.c [deleted file]
xen/common/kernel.c
xen/common/lib.c
xen/include/asm-i386/config.h
xen/include/asm-i386/processor.h
xen/include/asm-i386/types.h
xen/include/asm-x86_64/atomic.h
xen/include/asm-x86_64/config.h
xen/include/asm-x86_64/current.h
xen/include/asm-x86_64/desc.h
xen/include/asm-x86_64/io.h
xen/include/asm-x86_64/ldt.h
xen/include/asm-x86_64/page.h
xen/include/asm-x86_64/pci.h
xen/include/asm-x86_64/processor.h
xen/include/asm-x86_64/types.h
xen/include/asm-x86_64/uaccess.h
xen/include/hypervisor-ifs/arch-i386/hypervisor-if.h
xen/include/hypervisor-ifs/arch-x86_64/hypervisor-if.h
xen/include/hypervisor-ifs/dom0_ops.h
xen/include/xeno/lib.h
xen/include/xeno/types.h
xen/net/dev.c
xenolinux-2.4.25-sparse/arch/xeno/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/balloon/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.c [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.h [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/vbd.c [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.c [deleted file]
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.h [deleted file]
xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_vbd.c [deleted file]
xenolinux-2.4.25-sparse/arch/xeno/drivers/console/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/core.c [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c [deleted file]
xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/evtchn.c [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c [deleted file]
xenolinux-2.4.25-sparse/arch/xeno/drivers/network/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/Makefile [new file with mode: 0644]
xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/vnetif.c [new file with mode: 0644]

index 3e0cb1e20fdd8eea3a8ea6e7c28ea12bf66269f8..bac283ef59eb8f78543007fa3026426a4a43d13b 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/i386/apic.c
 3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/i386/boot/boot.S
 3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/i386/delay.c
+3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/i386/domain_page.c
 3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/i386/entry.S
 3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/i386/extable.c
 3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/i386/flushtlb.c
 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c
 3e6377e4i0c9GtKN65e99OtRbw3AZw xen/common/dom_mem_ops.c
 3ddb79bdYO5D8Av12NHqPeSviav7cg xen/common/domain.c
-3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/common/domain_page.c
 3ddb79bdeyutmaXEfpQvvxj7eQ0fCw xen/common/event.c
 3fba5b96H0khoxNiKbjdi0inpXV-Pw xen/common/event_channel.c
 3ddb79bd9drcFPVxd4w2GPOIjLlXpA xen/common/kernel.c
 3e6377f5xwPfYZkPHPrDbEq1PRN7uQ xenolinux-2.4.25-sparse/arch/xeno/drivers/balloon/Makefile
 3e6377f8Me8IqtvEhb70XFgOvqQH7A xenolinux-2.4.25-sparse/arch/xeno/drivers/balloon/balloon.c
 3e5a4e65iHEuC5sjFhj42XALYbLVRw xenolinux-2.4.25-sparse/arch/xeno/drivers/block/Makefile
-3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.c
-3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.h
-3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_vbd.c
+3e5a4e65pP5spJErBW69pJxSSdK9RA xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.c
+3e67f822FOPwqHiaRKbrskgWgoNL5g xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.h
+3e676eb5RXnHzSHgA1BvM0B1aIm4qg xenolinux-2.4.25-sparse/arch/xeno/drivers/block/vbd.c
 3e5a4e65G3e2s0ghPMgiJ-gBTUJ0uQ xenolinux-2.4.25-sparse/arch/xeno/drivers/console/Makefile
 3e5a4e651TH-SXHoufurnWjgl5bfOA xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c
 3e5a4e656nfFISThfbyXQOA6HN6YHw xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/Makefile
-3e5a4e65BXtftInNHUC2PjDfPhdZZA xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c
+3e5a4e65BXtftInNHUC2PjDfPhdZZA xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/core.c
 3e5a4e65gfn_ltB8ujHMVFApnTTNRQ xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/vfr.c
 40420a6ebRqDjufoN1WSJvolEW2Wjw xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/Makefile
-40420a73Wou6JlsZDiu6YwjYomsm7A xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
+40420a73Wou6JlsZDiu6YwjYomsm7A xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/evtchn.c
 3e5a4e65gZBRBB6RsSVg1c9iahigAw xenolinux-2.4.25-sparse/arch/xeno/drivers/network/Makefile
 3e5a4e65ZxKrbFetVB84JhrTyZ1YuQ xenolinux-2.4.25-sparse/arch/xeno/drivers/network/network.c
+405853f2wg7JXZJNltspMwOZJklxgw xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/Makefile
+405853f6nbeazrNyEWNHBuoSg2PiPA xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/vnetif.c
 3e5a4e65lWzkiPXsZdzPt2RNnJGG1g xenolinux-2.4.25-sparse/arch/xeno/kernel/Makefile
 3e5a4e65_hqfuxtGG8IUy6wRM86Ecg xenolinux-2.4.25-sparse/arch/xeno/kernel/entry.S
 3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg xenolinux-2.4.25-sparse/arch/xeno/kernel/head.S
index 786d372c3970fe6abb1eea4dabb995f4da6527b2..0659bb99c78dc633a2a3ede7a0ff9ae9d4a01b86 100644 (file)
@@ -378,32 +378,32 @@ int xc_linux_build(int xc_handle,
 
     /*
      * Initial register values:
-     *  DS,ES,FS,GS = FLAT_RING1_DS
-     *       CS:EIP = FLAT_RING1_CS:start_pc
-     *       SS:ESP = FLAT_RING1_DS:start_stack
+     *  DS,ES,FS,GS = FLAT_GUESTOS_DS
+     *       CS:EIP = FLAT_GUESTOS_CS:start_pc
+     *       SS:ESP = FLAT_GUESTOS_DS:start_stack
      *          ESI = start_info
      *  [EAX,EBX,ECX,EDX,EDI,EBP are zero]
      *       EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
      */
-    ctxt->i386_ctxt.ds = FLAT_RING1_DS;
-    ctxt->i386_ctxt.es = FLAT_RING1_DS;
-    ctxt->i386_ctxt.fs = FLAT_RING1_DS;
-    ctxt->i386_ctxt.gs = FLAT_RING1_DS;
-    ctxt->i386_ctxt.ss = FLAT_RING1_DS;
-    ctxt->i386_ctxt.cs = FLAT_RING1_CS;
-    ctxt->i386_ctxt.eip = load_addr;
-    ctxt->i386_ctxt.esp = virt_startinfo_addr;
-    ctxt->i386_ctxt.esi = virt_startinfo_addr;
-    ctxt->i386_ctxt.eflags = (1<<9) | (1<<2);
+    ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
+    ctxt->cpu_ctxt.eip = load_addr;
+    ctxt->cpu_ctxt.esp = virt_startinfo_addr;
+    ctxt->cpu_ctxt.esi = virt_startinfo_addr;
+    ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
 
     /* FPU is set up to default initial state. */
-    memset(ctxt->i387_ctxt, 0, sizeof(ctxt->i387_ctxt));
+    memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
 
     /* Virtual IDT is empty at start-of-day. */
     for ( i = 0; i < 256; i++ )
     {
         ctxt->trap_ctxt[i].vector = i;
-        ctxt->trap_ctxt[i].cs     = FLAT_RING1_CS;
+        ctxt->trap_ctxt[i].cs     = FLAT_GUESTOS_CS;
     }
     ctxt->fast_trap_idx = 0;
 
@@ -414,16 +414,16 @@ int xc_linux_build(int xc_handle,
     ctxt->gdt_ents = 0;
 
     /* Ring 1 stack is the initial stack. */
-    ctxt->ring1_ss  = FLAT_RING1_DS;
-    ctxt->ring1_esp = virt_startinfo_addr;
+    ctxt->guestos_ss  = FLAT_GUESTOS_DS;
+    ctxt->guestos_esp = virt_startinfo_addr;
 
     /* No debugging. */
     memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
 
     /* No callback handlers. */
-    ctxt->event_callback_cs     = FLAT_RING1_CS;
+    ctxt->event_callback_cs     = FLAT_GUESTOS_CS;
     ctxt->event_callback_eip    = 0;
-    ctxt->failsafe_callback_cs  = FLAT_RING1_CS;
+    ctxt->failsafe_callback_cs  = FLAT_GUESTOS_CS;
     ctxt->failsafe_callback_eip = 0;
 
     launch_op.u.builddomain.domain   = (domid_t)domid;
index 3b00a810114577a1898fa0f5005a1965247f816e..f0a2127bcc486d7c8e27350c6a72e325014145a1 100644 (file)
@@ -313,13 +313,13 @@ int xc_linux_restore(int xc_handle,
     verbose_printf("\b\b\b\b100%%\nMemory reloaded.\n");
 
     /* Uncanonicalise the suspend-record frame number and poke resume rec. */
-    pfn = ctxt.i386_ctxt.esi;
+    pfn = ctxt.cpu_ctxt.esi;
     if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
     {
         ERROR("Suspend record frame number is bad");
         goto out;
     }
-    ctxt.i386_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
+    ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
     p_srec = map_pfn_writeable(pm_handle, mfn);
     p_srec->resume_info.nr_pages    = nr_pfns;
     p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
@@ -370,13 +370,13 @@ int xc_linux_restore(int xc_handle,
 
     /*
      * Safety checking of saved context:
-     *  1. i386_ctxt is fine, as Xen checks that on context switch.
-     *  2. i387_ctxt is fine, as it can't hurt Xen.
+     *  1. cpu_ctxt is fine, as Xen checks that on context switch.
+     *  2. fpu_ctxt is fine, as it can't hurt Xen.
      *  3. trap_ctxt needs the code selectors checked.
      *  4. fast_trap_idx is checked by Xen.
      *  5. ldt base must be page-aligned, no more than 8192 ents, ...
      *  6. gdt already done, and further checking is done by Xen.
-     *  7. check that ring1_ss is safe.
+     *  7. check that guestos_ss is safe.
      *  8. pt_base is already done.
      *  9. debugregs are checked by Xen.
      *  10. callback code selectors need checking.
@@ -385,14 +385,14 @@ int xc_linux_restore(int xc_handle,
     {
         ctxt.trap_ctxt[i].vector = i;
         if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
-            ctxt.trap_ctxt[i].cs = FLAT_RING1_CS;
+            ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
     }
-    if ( (ctxt.ring1_ss & 3) == 0 )
-        ctxt.ring1_ss = FLAT_RING1_DS;
+    if ( (ctxt.guestos_ss & 3) == 0 )
+        ctxt.guestos_ss = FLAT_GUESTOS_DS;
     if ( (ctxt.event_callback_cs & 3) == 0 )
-        ctxt.event_callback_cs = FLAT_RING1_CS;
+        ctxt.event_callback_cs = FLAT_GUESTOS_CS;
     if ( (ctxt.failsafe_callback_cs & 3) == 0 )
-        ctxt.failsafe_callback_cs = FLAT_RING1_CS;
+        ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
     if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
          (ctxt.ldt_ents > 8192) ||
          (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
index 1695bd63c08b0ce3b3edb17da2be997931da5f52..aece21a01770148dc4fe00900ff83ad86bc46668 100644 (file)
@@ -182,14 +182,14 @@ int xc_linux_save(int xc_handle,
         goto out;
 
     /* Is the suspend-record MFN actually valid for this domain? */
-    if ( !check_pfn_ownership(xc_handle, ctxt.i386_ctxt.esi, domid) )
+    if ( !check_pfn_ownership(xc_handle, ctxt.cpu_ctxt.esi, domid) )
     {
         ERROR("Invalid state record pointer");
         goto out;
     }
 
     /* If the suspend-record MFN is okay then grab a copy of it to @srec. */
-    p_srec = map_pfn_readonly(pm_handle, ctxt.i386_ctxt.esi);
+    p_srec = map_pfn_readonly(pm_handle, ctxt.cpu_ctxt.esi);
     memcpy(&srec, p_srec, sizeof(srec));
     unmap_pfn(pm_handle, p_srec);
 
@@ -272,7 +272,7 @@ int xc_linux_save(int xc_handle,
     }
 
     /* Canonicalise the suspend-record frame number. */
-    if ( !translate_mfn_to_pfn(&ctxt.i386_ctxt.esi) )
+    if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) )
     {
         ERROR("State record is not in range of pseudophys map");
         goto out;
index 56fd35dbab03c91b6ca41d5c9eb95ae164f4730e..3472f32257c868c86693d00951006195e96e55eb 100644 (file)
@@ -273,32 +273,32 @@ int xc_netbsd_build(int xc_handle,
 
     /*
      * Initial register values:
-     *  DS,ES,FS,GS = FLAT_RING1_DS
-     *       CS:EIP = FLAT_RING1_CS:start_pc
-     *       SS:ESP = FLAT_RING1_DS:start_stack
+     *  DS,ES,FS,GS = FLAT_GUESTOS_DS
+     *       CS:EIP = FLAT_GUESTOS_CS:start_pc
+     *       SS:ESP = FLAT_GUESTOS_DS:start_stack
      *          ESI = start_info
      *  [EAX,EBX,ECX,EDX,EDI,EBP are zero]
      *       EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
      */
-    ctxt->i386_ctxt.ds = FLAT_RING1_DS;
-    ctxt->i386_ctxt.es = FLAT_RING1_DS;
-    ctxt->i386_ctxt.fs = FLAT_RING1_DS;
-    ctxt->i386_ctxt.gs = FLAT_RING1_DS;
-    ctxt->i386_ctxt.ss = FLAT_RING1_DS;
-    ctxt->i386_ctxt.cs = FLAT_RING1_CS;
-    ctxt->i386_ctxt.eip = load_addr;
-    ctxt->i386_ctxt.esp = virt_startinfo_addr;
-    ctxt->i386_ctxt.esi = virt_startinfo_addr;
-    ctxt->i386_ctxt.eflags = (1<<9) | (1<<2);
+    ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
+    ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
+    ctxt->cpu_ctxt.eip = load_addr;
+    ctxt->cpu_ctxt.esp = virt_startinfo_addr;
+    ctxt->cpu_ctxt.esi = virt_startinfo_addr;
+    ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
 
     /* FPU is set up to default initial state. */
-    memset(ctxt->i387_ctxt, 0, sizeof(ctxt->i387_ctxt));
+    memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
 
     /* Virtual IDT is empty at start-of-day. */
     for ( i = 0; i < 256; i++ )
     {
         ctxt->trap_ctxt[i].vector = i;
-        ctxt->trap_ctxt[i].cs     = FLAT_RING1_CS;
+        ctxt->trap_ctxt[i].cs     = FLAT_GUESTOS_CS;
     }
     ctxt->fast_trap_idx = 0;
 
@@ -309,16 +309,16 @@ int xc_netbsd_build(int xc_handle,
     ctxt->gdt_ents = 0;
 
     /* Ring 1 stack is the initial stack. */
-    ctxt->ring1_ss  = FLAT_RING1_DS;
-    ctxt->ring1_esp = virt_startinfo_addr;
+    ctxt->guestos_ss  = FLAT_GUESTOS_DS;
+    ctxt->guestos_esp = virt_startinfo_addr;
 
     /* No debugging. */
     memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
 
     /* No callback handlers. */
-    ctxt->event_callback_cs     = FLAT_RING1_CS;
+    ctxt->event_callback_cs     = FLAT_GUESTOS_CS;
     ctxt->event_callback_eip    = 0;
-    ctxt->failsafe_callback_cs  = FLAT_RING1_CS;
+    ctxt->failsafe_callback_cs  = FLAT_GUESTOS_CS;
     ctxt->failsafe_callback_eip = 0;
 
     launch_op.u.builddomain.domain   = (domid_t)domid;
diff --git a/xen/arch/i386/domain_page.c b/xen/arch/i386/domain_page.c
new file mode 100644 (file)
index 0000000..5e59745
--- /dev/null
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * domain_page.h
+ * 
+ * Allow temporary mapping of domain pages. Based on ideas from the
+ * Linux PKMAP code -- the copyrights and credits are retained below.
+ */
+
+/*
+ * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
+ *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+
+#include <xeno/config.h>
+#include <xeno/sched.h>
+#include <xeno/mm.h>
+#include <xeno/perfc.h>
+#include <asm/domain_page.h>
+#include <asm/pgalloc.h>
+
+unsigned long *mapcache;
+static unsigned int map_idx, shadow_map_idx[NR_CPUS];
+static spinlock_t map_lock = SPIN_LOCK_UNLOCKED;
+
+/* Use a spare PTE bit to mark entries ready for recycling. */
+#define READY_FOR_TLB_FLUSH (1<<10)
+
+static void flush_all_ready_maps(void)
+{
+    unsigned long *cache = mapcache;
+
+    /* A bit skanky -- depends on having an aligned PAGE_SIZE set of PTEs. */
+    do { if ( (*cache & READY_FOR_TLB_FLUSH) ) *cache = 0; }
+    while ( ((unsigned long)(++cache) & ~PAGE_MASK) != 0 );
+
+    perfc_incrc(domain_page_tlb_flush);
+    local_flush_tlb();
+}
+
+
+void *map_domain_mem(unsigned long pa)
+{
+    unsigned long va;
+    unsigned int idx, cpu = smp_processor_id();
+    unsigned long *cache = mapcache;
+    unsigned long flags;
+
+    spin_lock_irqsave(&map_lock, flags);
+
+    /* Has some other CPU caused a wrap? We must flush if so. */
+    if ( map_idx < shadow_map_idx[cpu] )
+    {
+        perfc_incrc(domain_page_tlb_flush);
+        local_flush_tlb();
+    }
+
+    for ( ; ; )
+    {
+        idx = map_idx = (map_idx + 1) & (MAPCACHE_ENTRIES - 1);
+        if ( idx == 0 ) flush_all_ready_maps();
+        if ( cache[idx] == 0 ) break;
+    }
+
+    cache[idx] = (pa & PAGE_MASK) | __PAGE_HYPERVISOR;
+
+    spin_unlock_irqrestore(&map_lock, flags);
+
+    shadow_map_idx[cpu] = idx;
+
+    va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT) + (pa & ~PAGE_MASK);
+    return (void *)va;
+}
+
+void unmap_domain_mem(void *va)
+{
+    unsigned int idx;
+    idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
+    mapcache[idx] |= READY_FOR_TLB_FLUSH;
+}
index 15dadf35b7dbc07df3162a7e5273938602a82ff6..e892c61953b8ef698ad01cc1b8c3dead23ebbdaf 100644 (file)
@@ -131,8 +131,8 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
     if ( (ss & 3) == 0 )
         return -EPERM;
 
-    current->thread.ss1  = ss;
-    current->thread.esp1 = esp;
+    current->thread.guestos_ss = ss;
+    current->thread.guestos_sp = esp;
     t->ss1  = ss;
     t->esp1 = esp;
 
index 09170307a7112bc8566889af9b53686182db0eef..bcbc5f550af2abebf7c3a64dc0799dba68107887 100644 (file)
@@ -264,8 +264,8 @@ void switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         SET_FAST_TRAP(&next_p->thread);
 
         /* Switch the guest OS ring-1 stack. */
-        tss->esp1 = next->esp1;
-        tss->ss1  = next->ss1;
+        tss->esp1 = next->guestos_sp;
+        tss->ss1  = next->guestos_ss;
 
         /* Maybe switch the debug registers. */
         if ( next->debugreg[7] )
index e359026371cfa04acc0511d2c15eece35acd3c2e..b39ead491c3f916b9e79f767037d47d65b61fc92 100644 (file)
@@ -290,23 +290,25 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
             {
                 rmb(); /* Ensure that we see saved register state. */
                 op->u.getdomaininfo.ctxt.flags = 0;
-                memcpy(&op->u.getdomaininfo.ctxt.i386_ctxt, 
+                memcpy(&op->u.getdomaininfo.ctxt.cpu_ctxt, 
                        &p->shared_info->execution_context,
                        sizeof(p->shared_info->execution_context));
                 if ( test_bit(PF_DONEFPUINIT, &p->flags) )
                     op->u.getdomaininfo.ctxt.flags |= ECF_I387_VALID;
-                memcpy(&op->u.getdomaininfo.ctxt.i387_ctxt,
+                memcpy(&op->u.getdomaininfo.ctxt.fpu_ctxt,
                        &p->thread.i387,
                        sizeof(p->thread.i387));
                 memcpy(&op->u.getdomaininfo.ctxt.trap_ctxt,
                        p->thread.traps,
                        sizeof(p->thread.traps));
+#ifdef ARCH_HAS_FAST_TRAP
                 if ( (p->thread.fast_trap_desc.a == 0) &&
                      (p->thread.fast_trap_desc.b == 0) )
                     op->u.getdomaininfo.ctxt.fast_trap_idx = 0;
                 else
                     op->u.getdomaininfo.ctxt.fast_trap_idx = 
                         p->thread.fast_trap_idx;
+#endif
                 op->u.getdomaininfo.ctxt.ldt_base = p->mm.ldt_base;
                 op->u.getdomaininfo.ctxt.ldt_ents = p->mm.ldt_ents;
                 op->u.getdomaininfo.ctxt.gdt_ents = 0;
@@ -318,8 +320,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
                     op->u.getdomaininfo.ctxt.gdt_ents = 
                         (GET_GDT_ENTRIES(p) + 1) >> 3;
                 }
-                op->u.getdomaininfo.ctxt.ring1_ss  = p->thread.ss1;
-                op->u.getdomaininfo.ctxt.ring1_esp = p->thread.esp1;
+                op->u.getdomaininfo.ctxt.guestos_ss  = p->thread.guestos_ss;
+                op->u.getdomaininfo.ctxt.guestos_esp = p->thread.guestos_sp;
                 op->u.getdomaininfo.ctxt.pt_base   = 
                     pagetable_val(p->mm.pagetable);
                 memcpy(op->u.getdomaininfo.ctxt.debugreg, 
@@ -371,6 +373,12 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
                 case PGT_l2_page_table:
                     op->u.getpageframeinfo.type = L2TAB;
                     break;
+                case PGT_l3_page_table:
+                    op->u.getpageframeinfo.type = L3TAB;
+                    break;
+                case PGT_l4_page_table:
+                    op->u.getpageframeinfo.type = L4TAB;
+                    break;
                 }
             }
             
index 53cea062850c1d25b044abb3be26c11563adcf05..8921ee246d0b63d8f0549e542678d19a962be843 100644 (file)
 #include <xeno/vbd.h>
 #include <asm/i387.h>
 
-/*
- * NB. No ring-3 access in initial guestOS pagetables. Note that we allow
- * ring-3 privileges in the page directories, so that the guestOS may later
- * decide to share a 4MB region with applications.
- */
+#if !defined(CONFIG_X86_64BITMODE)
+/* No ring-3 access in initial page tables. */
 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#else
+/* Allow ring-3 access in long mode as guest cannot use ring 1. */
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#endif
 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
 
 /* Both these structures are protected by the tasklist_lock. */
 rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
@@ -426,20 +429,20 @@ void free_all_dom_mem(struct task_struct *p)
             put_page(page);
 
         /*
-         * Forcibly invalidate L2 tables at this point to break circular
+         * Forcibly invalidate base page tables at this point to break circular
          * 'linear page table' references. This is okay because MMU structures
-         * are not shared across domains and this domain is now dead. Thus L2
+         * are not shared across domains and this domain is now dead. Thus base
          * tables are not in use so a non-zero count means circular reference.
          */
         y = page->type_and_flags;
         do {
             x = y;
             if ( likely((x & (PGT_type_mask|PGT_validated)) != 
-                        (PGT_l2_page_table|PGT_validated)) )
+                        (PGT_base_page_table|PGT_validated)) )
                 break;
             y = cmpxchg(&page->type_and_flags, x, x & ~PGT_validated);
             if ( likely(y == x) )
-                free_page_type(page, PGT_l2_page_table);
+                free_page_type(page, PGT_base_page_table);
         }
         while ( unlikely(y != x) );
 
@@ -504,7 +507,7 @@ void release_task(struct task_struct *p)
  */
 int final_setup_guestos(struct task_struct *p, dom0_builddomain_t *builddomain)
 {
-    unsigned long phys_l2tab;
+    unsigned long phys_basetab;
     int i;
 
     if ( test_bit(PF_CONSTRUCTED, &p->flags) )
@@ -514,16 +517,18 @@ int final_setup_guestos(struct task_struct *p, dom0_builddomain_t *builddomain)
     if ( builddomain->ctxt.flags & ECF_I387_VALID )
         set_bit(PF_DONEFPUINIT, &p->flags);
     memcpy(&p->shared_info->execution_context,
-           &builddomain->ctxt.i386_ctxt,
+           &builddomain->ctxt.cpu_ctxt,
            sizeof(p->shared_info->execution_context));
     memcpy(&p->thread.i387,
-           &builddomain->ctxt.i387_ctxt,
+           &builddomain->ctxt.fpu_ctxt,
            sizeof(p->thread.i387));
     memcpy(p->thread.traps,
            &builddomain->ctxt.trap_ctxt,
            sizeof(p->thread.traps));
+#ifdef ARCH_HAS_FAST_TRAP
     SET_DEFAULT_FAST_TRAP(&p->thread);
     (void)set_fast_trap(p, builddomain->ctxt.fast_trap_idx);
+#endif
     p->mm.ldt_base = builddomain->ctxt.ldt_base;
     p->mm.ldt_ents = builddomain->ctxt.ldt_ents;
     SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
@@ -532,8 +537,8 @@ int final_setup_guestos(struct task_struct *p, dom0_builddomain_t *builddomain)
         (void)set_gdt(p,
                       builddomain->ctxt.gdt_frames,
                       builddomain->ctxt.gdt_ents);
-    p->thread.ss1  = builddomain->ctxt.ring1_ss;
-    p->thread.esp1 = builddomain->ctxt.ring1_esp;
+    p->thread.guestos_ss = builddomain->ctxt.guestos_ss;
+    p->thread.guestos_sp = builddomain->ctxt.guestos_esp;
     for ( i = 0; i < 8; i++ )
         (void)set_debugreg(p, i, builddomain->ctxt.debugreg[i]);
     p->event_selector    = builddomain->ctxt.event_callback_cs;
@@ -541,10 +546,10 @@ int final_setup_guestos(struct task_struct *p, dom0_builddomain_t *builddomain)
     p->failsafe_selector = builddomain->ctxt.failsafe_callback_cs;
     p->failsafe_address  = builddomain->ctxt.failsafe_callback_eip;
     
-    phys_l2tab = builddomain->ctxt.pt_base;
-    p->mm.pagetable = mk_pagetable(phys_l2tab);
-    get_page_and_type(&frame_table[phys_l2tab>>PAGE_SHIFT], p, 
-                      PGT_l2_page_table);
+    phys_basetab = builddomain->ctxt.pt_base;
+    p->mm.pagetable = mk_pagetable(phys_basetab);
+    get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], p, 
+                      PGT_base_page_table);
 
     /* Set up the shared info structure. */
     update_dom_time(p->shared_info);
@@ -620,6 +625,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
     if ( strncmp(data_start, "XenoGues", 8) )
     {
         printk("DOM%llu: Invalid guest OS image\n", dom);
+        unmap_domain_mem(data_start);
         return -1;
     }
 
@@ -628,12 +634,14 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
     {
         printk("DOM%llu: Guest OS load address not page-aligned (%08lx)\n",
                dom, virt_load_address);
+        unmap_domain_mem(data_start);
         return -1;
     }
 
     if ( alloc_new_dom_mem(p, params->memory_kb) )
     {
         printk("DOM%llu: Not enough memory --- reduce dom0_mem ??\n", dom);
+        unmap_domain_mem(data_start);
         return -ENOMEM;
     }
 
@@ -650,6 +658,7 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
                dom, data_len>>20,
                (params->memory_kb)>>11,
                (params->memory_kb)>>10);
+        unmap_domain_mem(data_start);
         free_all_dom_mem(p);
         return -1;
     }
@@ -664,11 +673,11 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
      * We're basically forcing default RPLs to 1, so that our "what privilege
      * level are we returning to?" logic works.
      */
-    p->failsafe_selector = FLAT_RING1_CS;
-    p->event_selector    = FLAT_RING1_CS;
-    p->thread.ss1        = FLAT_RING1_DS;
+    p->failsafe_selector = FLAT_GUESTOS_CS;
+    p->event_selector    = FLAT_GUESTOS_CS;
+    p->thread.guestos_ss = FLAT_GUESTOS_DS;
     for ( i = 0; i < 256; i++ ) 
-        p->thread.traps[i].cs = FLAT_RING1_CS;
+        p->thread.traps[i].cs = FLAT_GUESTOS_CS;
 
     /*
      * WARNING: The new domain must have its 'processor' field
@@ -770,11 +779,11 @@ int setup_guestos(struct task_struct *p, dom0_createdomain_t *params,
        src++;
        if ( (((unsigned long)src) & (PAGE_SIZE-1)) == 0 )
         {
-           unmap_domain_mem( vsrc-1 );
-           vsrc = map_domain_mem( (unsigned long)src );
+           unmap_domain_mem(vsrc-1);
+           vsrc = map_domain_mem((unsigned long)src);
         }
     }
-    unmap_domain_mem( vsrc );
+    unmap_domain_mem(vsrc);
     
     /* Set up start info area. */
     memset(virt_startinfo_address, 0, sizeof(*virt_startinfo_address));
diff --git a/xen/common/domain_page.c b/xen/common/domain_page.c
deleted file mode 100644 (file)
index 5e59745..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/******************************************************************************
- * domain_page.h
- * 
- * Allow temporary mapping of domain pages. Based on ideas from the
- * Linux PKMAP code -- the copyrights and credits are retained below.
- */
-
-/*
- * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
- *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de *
- * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
- */
-
-#include <xeno/config.h>
-#include <xeno/sched.h>
-#include <xeno/mm.h>
-#include <xeno/perfc.h>
-#include <asm/domain_page.h>
-#include <asm/pgalloc.h>
-
-unsigned long *mapcache;
-static unsigned int map_idx, shadow_map_idx[NR_CPUS];
-static spinlock_t map_lock = SPIN_LOCK_UNLOCKED;
-
-/* Use a spare PTE bit to mark entries ready for recycling. */
-#define READY_FOR_TLB_FLUSH (1<<10)
-
-static void flush_all_ready_maps(void)
-{
-    unsigned long *cache = mapcache;
-
-    /* A bit skanky -- depends on having an aligned PAGE_SIZE set of PTEs. */
-    do { if ( (*cache & READY_FOR_TLB_FLUSH) ) *cache = 0; }
-    while ( ((unsigned long)(++cache) & ~PAGE_MASK) != 0 );
-
-    perfc_incrc(domain_page_tlb_flush);
-    local_flush_tlb();
-}
-
-
-void *map_domain_mem(unsigned long pa)
-{
-    unsigned long va;
-    unsigned int idx, cpu = smp_processor_id();
-    unsigned long *cache = mapcache;
-    unsigned long flags;
-
-    spin_lock_irqsave(&map_lock, flags);
-
-    /* Has some other CPU caused a wrap? We must flush if so. */
-    if ( map_idx < shadow_map_idx[cpu] )
-    {
-        perfc_incrc(domain_page_tlb_flush);
-        local_flush_tlb();
-    }
-
-    for ( ; ; )
-    {
-        idx = map_idx = (map_idx + 1) & (MAPCACHE_ENTRIES - 1);
-        if ( idx == 0 ) flush_all_ready_maps();
-        if ( cache[idx] == 0 ) break;
-    }
-
-    cache[idx] = (pa & PAGE_MASK) | __PAGE_HYPERVISOR;
-
-    spin_unlock_irqrestore(&map_lock, flags);
-
-    shadow_map_idx[cpu] = idx;
-
-    va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT) + (pa & ~PAGE_MASK);
-    return (void *)va;
-}
-
-void unmap_domain_mem(void *va)
-{
-    unsigned int idx;
-    idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
-    mapcache[idx] |= READY_FOR_TLB_FLUSH;
-}
index b963c6f5e994d948ebc84f7cfd2913a53632af87..f99f3fac32bbae0205952775e3e2ba0f513fb089 100644 (file)
@@ -190,16 +190,22 @@ void cmain(unsigned long magic, multiboot_info_t *mbi)
         for ( ; ; ) ;
     }
 
+    max_page = (mbi->mem_upper+1024) >> (PAGE_SHIFT - 10);
+
     /* The array of pfn_info structures must fit into the reserved area. */
-    if ( sizeof(struct pfn_info) > 24 )
+    if ( (sizeof(struct pfn_info) * max_page) > 
+         (FRAMETABLE_VIRT_END - FRAMETABLE_VIRT_START) )
     {
-        printk("'struct pfn_info' too large to fit in Xen address space!\n");
-        for ( ; ; ) ;
+        unsigned long new_max = 
+            (FRAMETABLE_VIRT_END - FRAMETABLE_VIRT_START) /
+            sizeof(struct pfn_info);
+       printk("Truncating available memory to %lu/%luMB\n", 
+               new_max >> (20 - PAGE_SHIFT), max_page >> (20 - PAGE_SHIFT));
+       max_page = new_max;
     }
 
     set_current(&idle0_task);
 
-    max_page = (mbi->mem_upper+1024) >> (PAGE_SHIFT - 10);
     init_frametable(max_page);
     printk("Initialised all memory on a %luMB machine\n",
            max_page >> (20-PAGE_SHIFT));
index 3d7cc8c00e24240414a3f62f58102589bbfe2812..6c8f57875d11c7c54953a8b4307c180026124d6b 100644 (file)
@@ -2,125 +2,6 @@
 #include <xeno/ctype.h>
 #include <xeno/lib.h>
 
-#if 0 // jws - now in string.c, string.h, asm/string.h 
-int memcmp(const void * cs,const void * ct,size_t count)
-{
-       const unsigned char *su1, *su2;
-       signed char res = 0;
-
-       for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
-               if ((res = *su1 - *su2) != 0)
-                       break;
-       return res;
-}
-
-void * memcpy(void * dest,const void *src,size_t count)
-{
-       char *tmp = (char *) dest, *s = (char *) src;
-
-       while (count--)
-               *tmp++ = *s++;
-
-       return dest;
-}
-
-int strncmp(const char * cs,const char * ct,size_t count)
-{
-       register signed char __res = 0;
-
-       while (count) {
-               if ((__res = *cs - *ct++) != 0 || !*cs++)
-                       break;
-               count--;
-       }
-
-       return __res;
-}
-
-int strcmp(const char * cs,const char * ct)
-{
-        register signed char __res;
-
-        while (1) {
-                if ((__res = *cs - *ct++) != 0 || !*cs++)
-                        break;
-        }
-
-        return __res;
-}
-
-char * strcpy(char * dest,const char *src)
-{
-        char *tmp = dest;
-
-        while ((*dest++ = *src++) != '\0')
-                /* nothing */;
-        return tmp;
-}
-
-char * strncpy(char * dest,const char *src,size_t count)
-{
-        char *tmp = dest;
-
-        while (count-- && (*dest++ = *src++) != '\0')
-                /* nothing */;
-
-        return tmp;
-}
-
-void * memset(void * s,int c,size_t count)
-{
-        char *xs = (char *) s;
-
-        while (count--)
-                *xs++ = c;
-
-        return s;
-}
-
-size_t strnlen(const char * s, size_t count)
-{
-        const char *sc;
-
-        for (sc = s; count-- && *sc != '\0'; ++sc)
-                /* nothing */;
-        return sc - s;
-}
-
-size_t strlen(const char * s)
-{
-       const char *sc;
-
-       for (sc = s; *sc != '\0'; ++sc)
-               /* nothing */;
-       return sc - s;
-}
-
-char * strchr(const char * s, int c)
-{
-        for(; *s != (char) c; ++s)
-                if (*s == '\0')
-                        return NULL;
-        return (char *) s;
-}
-
-char * strstr(const char * s1,const char * s2)
-{
-        int l1, l2;
-
-        l2 = strlen(s2);
-        if (!l2)
-                return (char *) s1;
-        l1 = strlen(s1);
-        while (l1 >= l2) {
-                l1--;
-                if (!memcmp(s1,s2,l2))
-                        return (char *) s1;
-                s1++;
-        }
-        return NULL;
-}
-#endif
 
 /* for inc/ctype.h */
 unsigned char _ctype[] = {
@@ -213,6 +94,7 @@ unsigned char *quad_to_str(unsigned long q, unsigned char *s)
 
 #include <asm/types.h>
 
+#if BITS_PER_LONG == 32
 
 /*
  * Depending on the desired operation, we view a `long long' (aka quad_t) in
@@ -526,7 +408,7 @@ __udivdi3(a, b)
         return (__qdivrem(a, b, (u64 *)0));
 }
 
-
+#endif /* BITS_PER_LONG == 32 */
 
 
 /* HASH/RANDOMISATION FUNCTION
@@ -535,8 +417,6 @@ __udivdi3(a, b)
  * See http://burlteburtle.net/bob/hash/evahash.html 
  */
 
-typedef unsigned long ub4;
-
 #define mix(a,b,c)                                      \
     do {                                                \
         a -= b; a -= c; a ^= (c>>13);                   \
@@ -550,9 +430,9 @@ typedef unsigned long ub4;
         c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
     } while ( 0 )
 
-unsigned long hash(unsigned char *k, unsigned long len)
+u32 hash(unsigned char *k, unsigned long len)
 {
-    unsigned long a, b, c, l;
+    u32 a, b, c, l;
 
     l = len;
     a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
@@ -560,9 +440,9 @@ unsigned long hash(unsigned char *k, unsigned long len)
 
     while ( l >= 12 )
     {
-        a += (k[0] + ((ub4)k[1]<<8) + ((ub4)k[2]<<16)  + ((ub4)k[3]<<24));
-        b += (k[4] + ((ub4)k[5]<<8) + ((ub4)k[6]<<16)  + ((ub4)k[7]<<24));
-        c += (k[8] + ((ub4)k[9]<<8) + ((ub4)k[10]<<16) + ((ub4)k[11]<<24));
+        a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16)  + ((u32)k[3]<<24));
+        b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16)  + ((u32)k[7]<<24));
+        c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
         mix(a,b,c);
         k += 12; l -= 12;
     }
@@ -570,17 +450,17 @@ unsigned long hash(unsigned char *k, unsigned long len)
     c += len;
     switch ( l )
     {
-    case 11: c+=((ub4)k[10]<<24);
-    case 10: c+=((ub4)k[9]<<16);
-    case 9 : c+=((ub4)k[8]<<8);
+    case 11: c+=((u32)k[10]<<24);
+    case 10: c+=((u32)k[9]<<16);
+    case 9 : c+=((u32)k[8]<<8);
         /* the first byte of c is reserved for the length */
-    case 8 : b+=((ub4)k[7]<<24);
-    case 7 : b+=((ub4)k[6]<<16);
-    case 6 : b+=((ub4)k[5]<<8);
+    case 8 : b+=((u32)k[7]<<24);
+    case 7 : b+=((u32)k[6]<<16);
+    case 6 : b+=((u32)k[5]<<8);
     case 5 : b+=k[4];
-    case 4 : a+=((ub4)k[3]<<24);
-    case 3 : a+=((ub4)k[2]<<16);
-    case 2 : a+=((ub4)k[1]<<8);
+    case 4 : a+=((u32)k[3]<<24);
+    case 3 : a+=((u32)k[2]<<16);
+    case 2 : a+=((u32)k[1]<<8);
     case 1 : a+=k[0];
         /* case 0: nothing left to add */
     }
index 3dd29864922c0e78b8cb697a8af80f59b0892434..3e70edceca3b4ee9da49d3f02e0c2b8b14ea1fc0 100644 (file)
   SYMBOL_NAME_LABEL(name)
 #endif
 
+#define PGT_base_page_table PGT_l2_page_table
+
 #define barrier() __asm__ __volatile__("": : :"memory")
 
 #define __HYPERVISOR_CS 0x0808
index c7df85aa2837054ec1b90afa5e627a4c52137394..0debc605db3fd95d6aa93b52505205ed56a0433c 100644 (file)
@@ -354,7 +354,7 @@ struct tss_struct {
 };
 
 struct thread_struct {
-    unsigned long esp1, ss1;
+    unsigned long guestos_sp, guestos_ss;
 /* Hardware debugging registers */
     unsigned long      debugreg[8];  /* %%db0-7 debug registers */
 /* floating point info */
index 2bd0f258b9e1d4b7b626ee90cf956d36e4d12fbf..0bba049f795dae5d864834d74886f476e9431f92 100644 (file)
@@ -3,6 +3,8 @@
 
 typedef unsigned short umode_t;
 
+typedef unsigned int size_t;
+
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
  * header files exported to user space
index f4eb85831255442584b2726ab537df3b047ce809..89e564a854e508407e0ddb9e89ae66f60d2639e3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __ARCH_I386_ATOMIC__
-#define __ARCH_I386_ATOMIC__
+#ifndef __ARCH_X86_64_ATOMIC__
+#define __ARCH_X86_64_ATOMIC__
 
 #include <xeno/config.h>
 
@@ -202,4 +202,4 @@ __asm__ __volatile__(LOCK "orl %0,%1" \
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
 
-#endif
+#endif /* __ARCH_X86_64_ATOMIC__ */
index 2fed6b79599b91e2be5939ebc097dcd7a5eb22b0..8b7c97612a37ae8a11afc87facb7552e6026c9e3 100644 (file)
@@ -2,12 +2,14 @@
  * config.h
  * 
  * A Linux-style configuration list.
+ * 
  */
 
 #ifndef __XENO_X86_64_CONFIG_H__
 #define __XENO_X86_64_CONFIG_H__
 
-#define CONFIG_X86 1
+#define CONFIG_X86    1
+#define CONFIG_X86_64BITMODE 1
 
 #define CONFIG_SMP 1
 #define CONFIG_X86_LOCAL_APIC 1
 #define __cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
 #define ____cacheline_aligned __cacheline_aligned
 
+#define PHYSICAL_ADDRESS_BITS 52
+#define MAX_PHYSICAL_ADDRESS (1 << PHYSICAL_ADDRESS_BITS)
+#define VIRTUAL_ADDRESS_BITS 48
+#define XEN_PAGE_SIZE 4096
+
+#define PTE_SIZE 8
+#define TOTAL_PTES (512ULL * 512 * 512 * 512)
+
+/* next PML4 from an _END address */
+#define PML4_BITS 39
+#define PML4_SPACE (1ULL << PML4_BITS)
+
 /*
- * Virtual addresses beyond this are not modifiable by guest OSes. The
- * machine->physical mapping table starts at this address, read-only.
+ * Memory layout
+ *
+ *   0x0000000000000000 - 0x00007fffffffffff Guest & user apps (128TB)
+ *    (Only for 32-bit guests)
+ *    0x00000000fc000000 - 0x00000000fc3fffff Machine/Physical 32-bit shadow (4MB)
+ *    0x00000000fc400000 - 0x00000000feffffff IO remap for 32-bit guests (44MB)
+ *    0x00000000ff000000 - 0x00000000ff3fffff 32-bit PTE shadow (4MB)
+ *
+ *   0xffff800000000000        - 0xffff807fffffffff Linear page table (512GB)
+ *   0xffff808000000000 - 0xffff80ffffffffff Reserved for shadow page table (512GB)
+ *
+ *   0xffff810000000000 - 0xffff82ffffffffff Xen PML4 slots 
+ *    0xffff810000000000 - 0xffff81003fffffff Xen hypervisor virtual space (1GB)
+ *    0xffff810040000000 - 0xffff81807fffffff Per-domain mappings (1GB)
+ *    0xffff810080000000 - 0xffff81387fffffff R/O physical map (224GB)
+ *    0xffff813880000000 - 0xffff81707fffffff R/W physical map (224GB)
+ *    0xffff817080000000 - 0xffff82c07fffffff Frame table (1344GB) 
+ *    0xffff82c080000000 - 0xffff82c0bfffffff I/O remap space (1GB)
+ *    0xffff82c0c0000000 - 0xffff82ffffffffff (253GB)
+ *
+ *   0xffff830000000000 - 0xffff87ffffffffff RESERVED (5TB)
+ *
+ *   0xffff880000000000 - ...                Physical 1:1 direct mapping (112TB max)
+ *    0xffff880000000000 - 0xffff880001000000 Low memory DMA region (16M)
+ *
+ *   0xfffff80000000000 - 0xffffffffffffffff Reserved for guest (8TB)
+ * 
+ * The requirement that we have a 1:1 map of physical memory limits
+ * the maximum memory size we can support.  With only 48 virtual address
+ * bits, and the assumption that guests will run users in positive address
+ * space, a contiguous 1:1 map can only live in the negative address space.
+ * Since we don't want to bump guests out of the very top of memory and
+ * force relocation, we can't use this entire space, and Xen has several
+ * heavy mapping that require PML4 slices.  Just to be safe, we reserve
+ * 16 PML4s each for Xen and the guest.  224 PML4s give us 112 terabytes
+ * of addressable memory.  Any high device physical addresses beyond this
+ * region can be mapped into the IO remap space or some of the reserved 
+ * 6TB region.
+ * 
+ * 112 TB is just 16 TB shy of the maximum physical memory supported
+ * on Linux 2.6.0, and should be enough for anybody.
+ *
+ * There are some additional constraints in the memory layout that require
+ * several changes from the i386 architecture.
+ *
+ * ACPI data and ACPI non-volatile storage must be placed in some region
+ * of memory below the 4GB mark.  Depending on the BIOS and system, we
+ * may have this located as low as 1GB.  This means allocating large
+ * chunks of physically contiguous memory from the direct mapping may not
+ * be possible. 
+ *
+ * The full frame table for 112TB of physical memory currently occupies
+ * 1344GB space.  This clearly can not be allocated in physically contiguous
+ * space, so it must be moved to a virtual address.
+ *
+ * Both copies of the machine->physical table must also be relocated.  
+ * (112 TB / 4k) * 8 bytes means that each copy of the physical map requires
+ * 224GB of space, thus it also must move to VM space.
+ *
+ * The physical pages used to allocate the page tables for the direct 1:1
+ * map may occupy (112TB / 2M) * 8 bytes = 448MB.  This is almost guaranteed
+ * to fit in contiguous physical memory, but these pages used to be allocated
+ * in the Xen monitor address space.  This means the Xen address space must
+ * accomodate up to ~500 MB, which means it also must move out of the
+ * direct mapped region. 
+ *
+ * Since both copies of the MPT, the frame table, and Xen now exist in
+ * purely virtual space, we have the added advantage of being able to
+ * map them to local pages on NUMA machines, or use NUMA aware memory
+ * allocation within Xen itself.
+ *
+ * Additionally, the 1:1 page table now exists contiguously in virtual
+ * space, but may be mapped to physically separated pages, allowing
+ * each node to contain the page tables for its own local memory.  Setting
+ * up this mapping presents a bit of a chicken-egg problem, but is possible
+ * as a future enhancement. 
+ *
+ * Zachary Amsden (zamsden@cisco.com)
+ *
  */
-#define HYPERVISOR_VIRT_START (0xFFFF800000000000ULL)
-                                                                                                
+
+/* Guest and user space */
+#define NSPACE_VIRT_START      0
+#define NSPACE_VIRT_END                (1ULL << (VIRTUAL_ADDRESS_BITS - 1))
+
+/* Priviledged space */
+#define ESPACE_VIRT_END                0
+#define ESPACE_VIRT_START      (ESPACE_VIRT_END-(1ULL << (VIRTUAL_ADDRESS_BITS-1)))
+
+/* reservations in e-space */
+#define GUEST_RESERVED_PML4S 16
+#define XEN_RESERVED_PML4S 16
+
+#define MAX_MEMORY_SIZE ((1ULL << (VIRTUAL_ADDRESS_BITS-1)) \
+                       -((GUEST_RESERVED_PML4S + XEN_RESERVED_PML4S) * PML4_SPACE))
+#define MAX_MEMORY_FRAMES (MAX_MEMORY_SIZE / XEN_PAGE_SIZE)
+
 /*
- * Xen exists in the highest 2GB of address space for RIP-relative
- * addressing
+ * Virtual addresses beyond this are not modifiable by guest OSes. 
  */
-#define XEN_VIRT_START        (0xFFFFFFFF80000000ULL)
-                                                                                                
+#define HYPERVISOR_VIRT_START ESPACE_VIRT_START
+#define HYPERVISOR_VIRT_END   (ESPACE_VIRT_END-(GUEST_RESERVED_PML4S * PML4_SPACE))
+
+/* First 512GB of virtual address space is used as a linear p.t. mapping. */
+#define LINEAR_PT_VIRT_START  (HYPERVISOR_VIRT_START)
+#define LINEAR_PT_VIRT_END    (LINEAR_PT_VIRT_START + (PTE_SIZE * TOTAL_PTES))
+
+/* Reserve some space for a shadow PT mapping */
+#define SHADOW_PT_VIRT_START  (LINEAR_PT_VIRT_END)
+#define SHADOW_PT_VIRT_END    (SHADOW_PT_VIRT_START + (PTE_SIZE * TOTAL_PTES))
+
+/* Xen exists in the first 1GB of the next PML4 space */
+#define MAX_MONITOR_ADDRESS   (1 * 1024 * 1024 * 1024)
+#define MONITOR_VIRT_START    (SHADOW_PT_VIRT_END)
+#define MONITOR_VIRT_END      (MONITOR_VIRT_START + MAX_MONITOR_ADDRESS)
+
+/* Next 1GB of virtual address space used for per-domain mappings (eg. GDT). */
+#define PERDOMAIN_VIRT_START  (MONITOR_VIRT_END)
+#define PERDOMAIN_VIRT_END    (PERDOMAIN_VIRT_START + (512 * 512 * 4096))
+#define GDT_VIRT_START        (PERDOMAIN_VIRT_START)
+#define GDT_VIRT_END          (GDT_VIRT_START + (128*1024))
+#define LDT_VIRT_START        (GDT_VIRT_END)
+#define LDT_VIRT_END          (LDT_VIRT_START + (128*1024))
+
 /*
- * First 4MB are mapped read-only for all. It's for the machine->physical
+ * First set of MPTs are mapped read-only for all. It's for the machine->physical
  * mapping table (MPT table). The following are virtual addresses.
  */
-#define READONLY_MPT_VIRT_START (HYPERVISOR_VIRT_START)
-#define READONLY_MPT_VIRT_END   (READONLY_MPT_VIRT_START + (4*1024*1024))
+#define READONLY_MPT_VIRT_START (PERDOMAIN_VIRT_END)
+#define READONLY_MPT_VIRT_END   (READONLY_MPT_VIRT_START + (PTE_SIZE * MAX_MEMORY_FRAMES))
+
+/* R/W machine->physical table */
+#define RDWR_MPT_VIRT_START   (READONLY_MPT_VIRT_END)
+#define RDWR_MPT_VIRT_END     (RDWR_MPT_VIRT_START + (PTE_SIZE * MAX_MEMORY_FRAMES))
+
+/* Frame table */
+#define FRAMETABLE_ENTRY_SIZE  (48)
+#define FRAMETABLE_VIRT_START (RDWR_MPT_VIRT_END)
+#define FRAMETABLE_VIRT_END   (FRAMETABLE_VIRT_START + (FRAMETABLE_ENTRY_SIZE * MAX_MEMORY_FRAMES))
+
+/* Next 1GB of virtual address space used for ioremap(). */
+#define IOREMAP_VIRT_START    (FRAMETABLE_VIRT_END)
+#define IOREMAP_VIRT_END      (IOREMAP_VIRT_START + (512 * 512 * 4096))
+
+/* And the virtual addresses for the direct-map region... */
+#define DIRECTMAP_VIRT_START  (ESPACE_VIRT_START + (XEN_RESERVED_PML4S * PML4_SPACE))
+#define DIRECTMAP_VIRT_END    (DIRECTMAP_VIRT_START + MAX_DIRECTMAP_ADDRESS)
+
 /*
- * Next 16MB is fixed monitor space, which is part of a 44MB direct-mapped
- * memory region. The following are machine addresses.
+ * Next is the direct-mapped memory region. The following are machine addresses.
  */
-#define MAX_MONITOR_ADDRESS   (16*1024*1024)
 #define MAX_DMA_ADDRESS       (16*1024*1024)
-#define MAX_DIRECTMAP_ADDRESS (44*1024*1024)
-/* And the virtual addresses for the direct-map region... */
-#define DIRECTMAP_VIRT_START  (READONLY_MPT_VIRT_END)
-#define DIRECTMAP_VIRT_END    (DIRECTMAP_VIRT_START + MAX_DIRECTMAP_ADDRESS)
-#define MONITOR_VIRT_START    (DIRECTMAP_VIRT_START)
-#define MONITOR_VIRT_END      (MONITOR_VIRT_START + MAX_MONITOR_ADDRESS)
-#define RDWR_MPT_VIRT_START   (MONITOR_VIRT_END)
-#define RDWR_MPT_VIRT_END     (RDWR_MPT_VIRT_START + (4*1024*1024))
-#define FRAMETABLE_VIRT_START (RDWR_MPT_VIRT_END)
-#define FRAMETABLE_VIRT_END   (DIRECTMAP_VIRT_END)
-/* Next 4MB of virtual address space is used as a linear p.t. mapping. */
-#define LINEAR_PT_VIRT_START  (DIRECTMAP_VIRT_END)
-#define LINEAR_PT_VIRT_END    (LINEAR_PT_VIRT_START + (4*1024*1024))
-/* Next 4MB of virtual address space used for per-domain mappings (eg. GDT). */
-#define PERDOMAIN_VIRT_START  (LINEAR_PT_VIRT_END)
-#define PERDOMAIN_VIRT_END    (PERDOMAIN_VIRT_START + (4*1024*1024))
-#define GDT_VIRT_START        (PERDOMAIN_VIRT_START)
-#define GDT_VIRT_END          (GDT_VIRT_START + (64*1024))
-#define LDT_VIRT_START        (GDT_VIRT_END)
-#define LDT_VIRT_END          (LDT_VIRT_START + (64*1024))
-/* Penultimate 4MB of virtual address space used for domain page mappings. */
-#define MAPCACHE_VIRT_START   (PERDOMAIN_VIRT_END)
-#define MAPCACHE_VIRT_END     (MAPCACHE_VIRT_START + (4*1024*1024))
-/* Final 4MB of virtual address space used for ioremap(). */
-#define IOREMAP_VIRT_START    (MAPCACHE_VIRT_END)
-#define IOREMAP_VIRT_END      (IOREMAP_VIRT_START + (4*1024*1024))
+#define MAX_DIRECTMAP_ADDRESS MAX_MEMORY_SIZE
+
+
 
 /*
- * Amount of slack domain memory to leave in system, in megabytes.
+ * Amount of slack domain memory to leave in system, in kilobytes.
  * Prevents a hard out-of-memory crunch for thinsg like network receive.
  */
 #define SLACK_DOMAIN_MEM_KILOBYTES 2048
 
+
+/*
+ * These will probably change in the future..
+ * locations for 32-bit guest compatibility mappings
+ */
+
+/* 4M of 32-bit machine-physical shadow in low 4G of VM space */
+#define SHADOW_MPT32_VIRT_START (0xfc000000)
+#define SHADOW_MPT32_VIRT_END   (SHADOW_MPT32_VIRT_START + (4 * 1024 * 1024))
+
+/* 44M of I/O remap for 32-bit drivers */
+#define IOREMAP_LOW_VIRT_START (SHADOW_MPT32_VIRT_END)
+#define IOREMAP_LOW_VIRT_END   (IOREMAP_LOW_VIRT_START + (44 * 1024 * 1024))
+
+/* 4M of 32-bit page table */
+#define SHADOW_PT32_VIRT_START (IOREMAP_LOW_VIRT_END)
+#define SHADOW_PT32_VIRT_END   (SHADOW_PT32_VIRT_START + (4 * 1024 * 1024))
+
+
 /* Linkage for x86 */
 #define FASTCALL(x)     x __attribute__((regparm(3)))
 #define asmlinkage        __attribute__((regparm(0)))
   SYMBOL_NAME_LABEL(name)
 #endif
 
+#define PGT_base_page_table PGT_l4_page_table
+
 #define barrier() __asm__ __volatile__("": : :"memory")
 
 /*
index dd288ca8b3a3adcb2df6a65848a5c0dbaff9a5ee..d5ffb0720a7a66b9e2cf5eaf98324eb5585d78b4 100644 (file)
@@ -26,7 +26,7 @@ static inline void set_current(struct task_struct *p)
 static inline execution_context_t *get_execution_context(void)
 {
     execution_context_t *execution_context;
-    __asm__( "andq %%rsp,%0; addl %2,%0"
+    __asm__( "andq %%rsp,%0; addq %2,%0"
            : "=r" (execution_context)
            : "0" (~(STACK_SIZE-1)), "i" (STACK_SIZE-STACK_RESERVED) ); 
     return execution_context;
@@ -42,7 +42,7 @@ static inline unsigned long get_stack_top(void)
 
 #define schedule_tail(_p)                                         \
     __asm__ __volatile__ (                                        \
-        "andq %%rsp,%0; addq %2,%0; movl %0,%%rsp; jmp *%1"       \
+        "andq %%rsp,%0; addq %2,%0; movq %0,%%rsp; jmp *%1"       \
         : : "r" (~(STACK_SIZE-1)),                                \
             "r" (unlikely(is_idle_task((_p))) ?                   \
                                 continue_cpu_idle_loop :          \
index ef864de036835b8a860251e69347838c3e28de11..e8556e976edbcb24eafea43eb1bae2a385840196 100644 (file)
@@ -8,7 +8,7 @@
 #define __FIRST_PER_CPU_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
 
 #define __CPU_DESC_INDEX(x,field) \
-       ((x) * sizeof(struct per_cpu_gdt) + offsetof(struct per_cpu_gdt, field) + (FIRST_PER_CPU_ENTRY*8))
+       ((x) * sizeof(struct per_cpu_gdt) + offsetof(struct per_cpu_gdt, field) + (__FIRST_PER_CPU_ENTRY*8))
 #define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
 
 #define load_TR(cpu) asm volatile("ltr %w0"::"r" (__CPU_DESC_INDEX(cpu, tss)));
index 21c22876a2c9a1b5aae470556d4bad8ee78df5a8..aa580dd71acbb42159619398167ba3ba80ca0f28 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_IO_H
 
 #include <xeno/config.h>
+#include <asm/page.h>
 
 /*
  * This file contains the definitions for the x86 IO instructions
@@ -139,9 +140,12 @@ extern inline void * phys_to_virt(unsigned long address)
 #ifdef CONFIG_DISCONTIGMEM
 #include <asm/mmzone.h>
 #else
-#define page_to_phys(page)     (((page) - frame_table) << PAGE_SHIFT)
+#define page_to_phys(page)      (((page) - frame_table) << PAGE_SHIFT)
 #endif
 
+#define page_to_pfn(page)       ((unsigned long)((_page) - frame_table))
+#define page_to_virt(page)      (phys_to_virt(page_to_phys(_page)))
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
index 7a345ceb40e80a7c63786413e8271ed6f43cd92a..e0f139829e67af25ebf67a81ca9b72fc522690dd 100644 (file)
@@ -9,7 +9,7 @@ static inline void load_LDT(struct task_struct *p)
 
     if ( (ents = p->mm.ldt_ents) == 0 )
     {
-        __asm__ __volatile__ ( "lldt %%rax" : : "a" (0) );
+        __asm__ __volatile__ ( "lldt %w0" : : "r" (0) );
     }
     else
     {
@@ -17,17 +17,17 @@ static inline void load_LDT(struct task_struct *p)
        struct ldttss_desc *desc;
 
         cpu = smp_processor_id();
-        desc = (struct desc_struct *)((char *)GET_GDT_ADDRESS(p) + __CPU_DESC_INDEX(cpu, ldt));
+        desc = (struct ldttss_desc *)((char *)GET_GDT_ADDRESS(p) + __CPU_DESC_INDEX(cpu, ldt));
        desc->limit0 = ents*8-1;
        desc->base0 = LDT_VIRT_START&0xffff;
        desc->base1 = (LDT_VIRT_START&0xff0000)>>16;
        desc->type = DESC_LDT;
        desc->dpl = 0;
        desc->p = 1;
-       desc->limit = 0;
+       desc->limit1 = 0;
        desc->zero0 = 0;
        desc->g = 0;
-       desc->base2 = (LDT_VIRST_START&0xff000000)>>24;
+       desc->base2 = (LDT_VIRT_START&0xff000000)>>24;
        desc->base3 = LDT_VIRT_START>>32;
        desc->zero1 = 0;
        __load_LDT(cpu);
index b016b635b2867907576c8eb05733604f62ba0a5c..d7cb5c6b3f305c9d2a435747c5cdbbfbce5e72d7 100644 (file)
@@ -265,7 +265,6 @@ struct bug_frame {
 #ifndef CONFIG_DISCONTIGMEM
 #define virt_to_page(kaddr)    (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
 #define pfn_to_page(pfn)       (frame_table + (pfn)) 
-#define page_to_pfn(page)   ((page) - frame_table)
 #define page_address(_p)        (__va(((_p) - frame_table) << PAGE_SHIFT))
 #define VALID_PAGE(page)       (((page) - frame_table) < max_mapnr)
 #endif
index 5c931adb365ded97d3cef43968b758c9dbf15b97..ffb30f50ba89baa68352e2ff8e89ab397856ed7a 100644 (file)
@@ -27,10 +27,8 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
 #include <xeno/types.h>
 #include <xeno/slab.h>
 #include <asm/scatterlist.h>
-/*#include <xeno/string.h>*/
 #include <asm/io.h>
 #include <asm/page.h>
-#include <asm/mmzone.h>
 
 struct pci_dev;
 extern int force_mmu;
@@ -96,14 +94,16 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev,
                                       dma_addr_t dma_handle,
                                       size_t size, int direction)
 {
-       BUG_ON(direction == PCI_DMA_NONE); 
+       if (direction == PCI_DMA_NONE)
+               out_of_line_bug();
 } 
 
 static inline void pci_dma_sync_sg(struct pci_dev *hwdev, 
                                   struct scatterlist *sg,
                                   int nelems, int direction)
 { 
-       BUG_ON(direction == PCI_DMA_NONE); 
+       if (direction == PCI_DMA_NONE)
+               out_of_line_bug();
 } 
 
 /* The PCI address space does equal the physical memory
@@ -162,6 +162,19 @@ static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct pfn_info *pa
 
 #define BAD_DMA_ADDRESS (-1UL)
 
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+static inline void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg,
+                                  int nents, int dir)
+{
+       if (dir == PCI_DMA_NONE)
+               out_of_line_bug();
+}
+       
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
@@ -181,18 +194,20 @@ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                             int nents, int direction)
 {
        int i;
-                                                                                          
-       BUG_ON(direction == PCI_DMA_NONE);
-                                                                                          
+
+       if (direction == PCI_DMA_NONE)
+               out_of_line_bug();
+
        /*
         * temporary 2.4 hack
         */
        for (i = 0; i < nents; i++ ) {
                struct scatterlist *s = &sg[i];
                void *addr = s->address;
-               if (addr)
-                       BUG_ON(s->page || s->offset);
-               else if (s->page)
+               if (addr) {
+                       if (s->page || s->offset)
+                               out_of_line_bug();
+               } else if (s->page)
                        addr = page_address(s->page) + s->offset;
 #if 0
                /* Invalid check, since address==0 is valid. */
@@ -209,17 +224,6 @@ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
        pci_unmap_sg(hwdev, sg, i, direction);
        return 0;
 }
-                                                                                          
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg,
-                                  int nents, int dir)
-{
-       if (direction == PCI_DMA_NONE)
-               out_of_line_bug();
-}
 
        
 /* Make physical memory consistent for a single
@@ -259,11 +263,6 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 
 #endif
 
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                     int nents, int direction);
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                        int nents, int direction);
-
 #define pci_unmap_page pci_unmap_single
 
 /* Return whether the given PCI device DMA address mask can
@@ -297,6 +296,7 @@ pci_dac_page_to_dma(struct pci_dev *pdev, struct pfn_info *page, unsigned long o
 static __inline__ struct pfn_info *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
+       unsigned long poff = (dma_addr >> PAGE_SHIFT);
        return frame_table + poff;
 }
 
index 47d0f751e97b68a8cd9d98a6b472e4b606f12dc3..16d095f6c85a9a912e368753e8493959c1b8af43 100644 (file)
@@ -340,7 +340,8 @@ struct tss_struct {
 } __attribute__((packed)) ____cacheline_aligned;
 
 struct thread_struct {
-       unsigned long   rsp0;
+       unsigned long   guestos_sp;
+       unsigned long   guestos_ss;
        unsigned long   rip;
        unsigned long   rsp;
        unsigned long   userrsp;        /* Copy from PDA */ 
index 1b865c48fc10b5e627e5f32acd67dc3eea417702..ea7aac72f7f5d4c1a6ab717b8e804612344ac4e9 100644 (file)
@@ -3,6 +3,8 @@
 
 typedef unsigned short umode_t;
 
+typedef unsigned long size_t;
+
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
  * header files exported to user space
index 56a7a42aeb5e50cd41556e53fe30e844732472f8..49a5db93c24f71349c6134be4ade83eb56bfb432 100644 (file)
@@ -103,11 +103,11 @@ extern void __get_user_8(void);
 ({     long __val_gu;                                                  \
        int __ret_gu=1;                                                 \
        switch(sizeof (*(ptr))) {                                       \
-       case 1:  _ret_gu=copy_from_user(&__val_gu,ptr,1);break;         \
-       case 2:  _ret_gu=copy_from_user(&__val_gu,ptr,2);break;         \
-       case 4:  _ret_gu=copy_from_user(&__val_gu,ptr,4);break;         \
-       case 8:  _ret_gu=copy_from_user(&__val_gu,ptr,8);break;         \
-       default: _ret_gu=copy_from_user(&__val_gu,ptr,sizeof(*(ptr)));break;\
++      case 1:  __ret_gu=copy_from_user(&__val_gu,ptr,1);break;                \
++      case 2:  __ret_gu=copy_from_user(&__val_gu,ptr,2);break;                \
++      case 4:  __ret_gu=copy_from_user(&__val_gu,ptr,4);break;                \
++      case 8:  __ret_gu=copy_from_user(&__val_gu,ptr,8);break;                \
++      default: __ret_gu=copy_from_user(&__val_gu,ptr,sizeof(*(ptr)));break;\
        /*case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;*/      \
        /*case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;*/      \
        /*case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;*/      \
index e3b32cb4b5d37d37579a2fb9760868a9bb9652fc..a06020cd96ae0d6156f0487b4cabe942c3833374 100644 (file)
 #define FLAT_RING3_CS 0x082b    /* GDT index 261 */
 #define FLAT_RING3_DS 0x0833    /* GDT index 262 */
 
+#define FLAT_GUESTOS_CS FLAT_RING1_CS
+#define FLAT_GUESTOS_DS FLAT_RING1_DS
+#define FLAT_USER_CS    FLAT_RING3_CS
+#define FLAT_USER_DS    FLAT_RING3_DS
+
 /* And the trap vector is... */
 #define TRAP_INSTR "int $0x82"
 
@@ -99,13 +104,13 @@ typedef struct full_execution_context_st
 {
 #define ECF_I387_VALID (1<<0)
     unsigned long flags;
-    execution_context_t i386_ctxt;          /* User-level CPU registers     */
-    char          i387_ctxt[256];           /* User-level FPU registers     */
+    execution_context_t cpu_ctxt;           /* User-level CPU registers     */
+    char          fpu_ctxt[256];            /* User-level FPU registers     */
     trap_info_t   trap_ctxt[256];           /* Virtual IDT                  */
     unsigned int  fast_trap_idx;            /* "Fast trap" vector offset    */
     unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
     unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
-    unsigned long ring1_ss, ring1_esp;      /* Virtual TSS (only SS1/ESP1)  */
+    unsigned long guestos_ss, guestos_esp;  /* Virtual TSS (only SS1/ESP1)  */
     unsigned long pt_base;                  /* CR3 (pagetable base)         */
     unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
     unsigned long event_callback_cs;        /* CS:EIP of event callback     */
@@ -114,6 +119,8 @@ typedef struct full_execution_context_st
     unsigned long failsafe_callback_eip;
 } full_execution_context_t;
 
+#define ARCH_HAS_FAST_TRAP
+
 #endif
 
 #endif
index 0a1101b314a9f240a2be350b83b5fe7df6262f4e..94c031120acf90d89161184f877d6da9333f3133 100644 (file)
 #define FLAT_RING3_CS64 0x082b /* GDT index 261 */
 #define FLAT_RING3_DS 0x0833   /* GDT index 262 */
 
+#define FLAT_GUESTOS_DS   FLAT_RING3_DS
+#define FLAT_GUESTOS_CS   FLAT_RING3_CS64
+#define FLAT_GUESTOS_CS32 FLAT_RING3_CS32
+
+#define FLAT_USER_DS      FLAT_RING3_DS
+#define FLAT_USER_CS      FLAT_RING3_CS64
+#define FLAT_USER_CS32    FLAT_RING3_CS32
 
 /* And the trap vector is... */
 #define TRAP_INSTR "syscall"
 
 
 #ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#define machine_to_phys_mapping ((unsigned long *)0xffff810000000000ULL)
 #endif
 
 #ifndef __ASSEMBLY__
@@ -98,13 +105,12 @@ typedef struct full_execution_context_st
 {
 #define ECF_I387_VALID (1<<0)
     unsigned long flags;
-    execution_context_t x86_64_ctxt;          /* User-level CPU registers     */
-    char          i387_ctxt[512];           /* User-level FPU registers     */
+    execution_context_t cpu_ctxt;           /* User-level CPU registers     */
+    char          fpu_ctxt[512];            /* User-level FPU registers     */
     trap_info_t   trap_ctxt[256];           /* Virtual IDT                  */
-    unsigned int  fast_trap_idx;            /* "Fast trap" vector offset    */
     unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
     unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
-    unsigned long ring1_ss, ring1_esp;      /* Virtual TSS (only SS1/ESP1)  */
+    unsigned long guestos_ss, guestos_esp;  /* Virtual TSS (only SS1/ESP1)  */
     unsigned long pt_base;                  /* CR3 (pagetable base)         */
     unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
     unsigned long event_callback_cs;        /* CS:EIP of event callback     */
index 1345293284ba2a3194e5faccc3e63f8678ffc316..8e84f3833675c17f643385689d67eeaa96a9f843 100644 (file)
@@ -116,10 +116,11 @@ typedef struct dom0_getdomaininfo_st
 typedef struct dom0_getpageframeinfo_st
 {
     /* IN variables. */
-    unsigned long pfn;          /* Machine page frame number to query.       */
+    unsigned long pfn;     /* Machine page frame number to query.       */
     domid_t domain;        /* To which domain does the frame belong?    */
     /* OUT variables. */
-    enum { NONE, L1TAB, L2TAB } type; /* Is the page PINNED to a type?       */
+    /* Is the page PINNED to a type? */
+    enum { NONE, L1TAB, L2TAB, L3TAB, L4TAB } type;
 } dom0_getpageframeinfo_t;
 
 #define DOM0_IOPL             14
index c3fe557974fc00fbc6bf9fa5dbc95de9dfa22268..f29964f43107f37b943a5f7a7e73c1a2d103499e 100644 (file)
@@ -51,6 +51,6 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
 long long simple_strtoll(const char *cp,char **endp,unsigned int base);
 
 /* Produce a 32-bit hash from a key string 'k' of length 'len' bytes. */
-unsigned long hash(unsigned char *k, unsigned long len);
+u32 hash(unsigned char *k, unsigned long len);
 
 #endif /* __LIB_H__ */
index c5f8d5586d307aab56042863cf5028660c5cc611..0299f741369ee9725a1db945e0e7161476f7fb3e 100644 (file)
@@ -14,8 +14,6 @@
 #define LONG_MIN        (-LONG_MAX - 1)
 #define ULONG_MAX       (~0UL)
 
-typedef unsigned int size_t;
-
 /* bsd */
 typedef unsigned char           u_char;
 typedef unsigned short          u_short;
index fbd9be63c96f4ffb3ede9e64885839c4b7591790..1bd91206724d192bb6b6b6e6927e7686a3cdd892 100644 (file)
@@ -627,7 +627,7 @@ static void net_rx_action(struct softirq_action *h)
          * for ethernet header, plus any other alignment padding added by the
          * driver.
          */
-        offset = (int)skb->data & ~PAGE_MASK; 
+        offset = (int)(long)skb->data & ~PAGE_MASK; 
         skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << 
                                           PAGE_SHIFT));
         skb->data = skb->nh.raw = skb->head + offset;
index 6a1e501b59a3f91fcfed9133142b60b728a1d49f..a2e6a0e0cd134ffe571328ca4dbef47c5429a941 100644 (file)
@@ -51,20 +51,21 @@ HEAD := arch/xeno/kernel/head.o arch/xeno/kernel/init_task.o
 SUBDIRS += arch/xeno/kernel arch/xeno/mm arch/xeno/lib
 SUBDIRS += arch/xeno/drivers/console arch/xeno/drivers/network
 SUBDIRS += arch/xeno/drivers/evtchn arch/xeno/drivers/block
-SUBDIRS += arch/xeno/drivers/balloon
+SUBDIRS += arch/xeno/drivers/balloon arch/xeno/drivers/vnetif
 ifdef CONFIG_XENO_PRIV
 SUBDIRS += arch/xeno/drivers/dom0 
 endif
 
 CORE_FILES += arch/xeno/kernel/kernel.o arch/xeno/mm/mm.o
-CORE_FILES += arch/xeno/drivers/evtchn/evtchn.o
-CORE_FILES += arch/xeno/drivers/console/con.o
-CORE_FILES += arch/xeno/drivers/block/blk.o
-CORE_FILES += arch/xeno/drivers/network/net.o
+CORE_FILES += arch/xeno/drivers/evtchn/drv.o
+CORE_FILES += arch/xeno/drivers/console/drv.o
+CORE_FILES += arch/xeno/drivers/block/drv.o
+CORE_FILES += arch/xeno/drivers/network/drv.o
+CORE_FILES += arch/xeno/drivers/vnetif/drv.o
 ifdef CONFIG_XENO_PRIV
-CORE_FILES += arch/xeno/drivers/dom0/dom0.o
+CORE_FILES += arch/xeno/drivers/dom0/drv.o
 endif
-CORE_FILES += arch/xeno/drivers/balloon/balloon_driver.o
+CORE_FILES += arch/xeno/drivers/balloon/drv.o
 LIBS := $(TOPDIR)/arch/xeno/lib/lib.a $(LIBS) $(TOPDIR)/arch/xeno/lib/lib.a
 
 arch/xeno/kernel: dummy
index f780a515e068844681ff439084bf64b0ccd35fb9..9fb22279788d8a22dd987b11479738184d87b7da 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := balloon_driver.o
+O_TARGET := drv.o
 obj-y := balloon.o
 include $(TOPDIR)/Rules.make
index 7c87e099c774802d250d40373f29babe1a1959e7..35986ca54a6a7b903d139eb6cedbc9494392cbc1 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := blk.o
-obj-y := xl_block.o xl_vbd.o
+O_TARGET := drv.o
+obj-y := block.o vbd.o
 include $(TOPDIR)/Rules.make
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.c
new file mode 100644 (file)
index 0000000..c01a44d
--- /dev/null
@@ -0,0 +1,621 @@
+/******************************************************************************
+ * block.c
+ * 
+ * Xenolinux virtual block-device driver.
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ */
+
+#include "block.h"
+#include <linux/blk.h>
+#include <linux/cdrom.h>
+#include <linux/tqueue.h>
+#include <linux/sched.h>
+#include <scsi/scsi.h>
+
+#include <linux/interrupt.h>
+
+typedef unsigned char byte; /* from linux/ide.h */
+
+#define XLBLK_RESPONSE_IRQ HYPEREVENT_IRQ(_EVENT_BLKDEV)
+#define XLBLK_UPDATE_IRQ   HYPEREVENT_IRQ(_EVENT_VBD_UPD)
+#define DEBUG_IRQ          HYPEREVENT_IRQ(_EVENT_DEBUG)
+
+#define STATE_ACTIVE    0
+#define STATE_SUSPENDED 1
+#define STATE_CLOSED    2
+static unsigned int state = STATE_SUSPENDED;
+
+static blk_ring_t *blk_ring;
+static BLK_RING_IDX resp_cons; /* Response consumer for comms ring. */
+static BLK_RING_IDX req_prod;  /* Private request producer.         */
+
+/* We plug the I/O ring if the driver is suspended or if the ring is full. */
+#define RING_PLUGGED (((req_prod - resp_cons) == BLK_RING_SIZE) || \
+                      (state != STATE_ACTIVE))
+
+
+/*
+ * Request queues with outstanding work, but ring is currently full.
+ * We need no special lock here, as we always access this with the
+ * io_request_lock held. We only need a small maximum list.
+ */
+#define MAX_PENDING 8
+static request_queue_t *pending_queues[MAX_PENDING];
+static int nr_pending;
+
+static kdev_t        sg_dev;
+static int           sg_operation = -1;
+static unsigned long sg_next_sect;
+#define DISABLE_SCATTERGATHER() (sg_operation = -1)
+
+static inline void signal_requests_to_xen(void)
+{
+    block_io_op_t op; 
+
+    DISABLE_SCATTERGATHER();
+    blk_ring->req_prod = req_prod;
+
+    op.cmd = BLOCK_IO_OP_SIGNAL; 
+    HYPERVISOR_block_io_op(&op);
+    return;
+}
+
+
+/*
+ * xlblk_update_int/update-vbds_task - handle VBD update events from Xen
+ * 
+ * Schedule a task for keventd to run, which will update the VBDs and perform 
+ * the corresponding updates to our view of VBD state, so the XenoLinux will 
+ * respond to changes / additions / deletions to the set of VBDs automatically.
+ */
+static struct tq_struct update_tq;
+static void update_vbds_task(void *unused)
+{ 
+    xlvbd_update_vbds();
+}
+static void xlblk_update_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+    update_tq.routine = update_vbds_task;
+    schedule_task(&update_tq);
+}
+
+
+int xenolinux_block_open(struct inode *inode, struct file *filep)
+{
+    short xldev = inode->i_rdev; 
+    struct gendisk *gd = get_gendisk(xldev);
+    xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+    short minor = MINOR(xldev); 
+
+    if ( gd->part[minor].nr_sects == 0 )
+    { 
+        /*
+         * Device either doesn't exist, or has zero capacity; we use a few
+         * cheesy heuristics to return the relevant error code
+         */
+        if ( (gd->sizes[minor >> gd->minor_shift] != 0) ||
+             ((minor & (gd->max_p - 1)) != 0) )
+        { 
+            /*
+             * We have a real device, but no such partition, or we just have a
+             * partition number so guess this is the problem.
+             */
+            return -ENXIO;     /* no such device or address */
+        }
+        else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE )
+        {
+            /* This is a removable device => assume that media is missing. */ 
+            return -ENOMEDIUM; /* media not present (this is a guess) */
+        } 
+        else
+        { 
+            /* Just go for the general 'no such device' error. */
+            return -ENODEV;    /* no such device */
+        }
+    }
+    
+    /* Update of usage count is protected by per-device semaphore. */
+    disk->usage++;
+
+    return 0;
+}
+
+
+int xenolinux_block_release(struct inode *inode, struct file *filep)
+{
+    xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+
+    /*
+     * When usage drops to zero it may allow more VBD updates to occur.
+     * Update of usage count is protected by a per-device semaphore.
+     */
+    if ( --disk->usage == 0 )
+    {
+        update_tq.routine = update_vbds_task;
+        schedule_task(&update_tq);
+    }
+
+    return 0;
+}
+
+
+int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+                          unsigned command, unsigned long argument)
+{
+    kdev_t dev = inode->i_rdev;
+    struct hd_geometry *geo = (struct hd_geometry *)argument;
+    struct gendisk *gd;     
+    struct hd_struct *part; 
+    int i;
+
+    /* NB. No need to check permissions. That is done for us. */
+    
+    DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
+                  command, (long) argument, dev); 
+  
+    gd = get_gendisk(dev);
+    part = &gd->part[MINOR(dev)]; 
+
+    switch ( command )
+    {
+    case BLKGETSIZE:
+        DPRINTK_IOCTL("   BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects); 
+        return put_user(part->nr_sects, (unsigned long *) argument);
+
+    case BLKGETSIZE64:
+        DPRINTK_IOCTL("   BLKGETSIZE64: %x %llx\n", BLKGETSIZE64,
+                      (u64)part->nr_sects * 512);
+        return put_user((u64)part->nr_sects * 512, (u64 *) argument);
+
+    case BLKRRPART:                               /* re-read partition table */
+        DPRINTK_IOCTL("   BLKRRPART: %x\n", BLKRRPART);
+        return xenolinux_block_revalidate(dev);
+
+    case BLKSSZGET:
+        return hardsect_size[MAJOR(dev)][MINOR(dev)]; 
+
+    case BLKBSZGET:                                        /* get block size */
+        DPRINTK_IOCTL("   BLKBSZGET: %x\n", BLKBSZGET);
+        break;
+
+    case BLKBSZSET:                                        /* set block size */
+        DPRINTK_IOCTL("   BLKBSZSET: %x\n", BLKBSZSET);
+        break;
+
+    case BLKRASET:                                         /* set read-ahead */
+        DPRINTK_IOCTL("   BLKRASET: %x\n", BLKRASET);
+        break;
+
+    case BLKRAGET:                                         /* get read-ahead */
+        DPRINTK_IOCTL("   BLKRAFET: %x\n", BLKRAGET);
+        break;
+
+    case HDIO_GETGEO:
+        /* note: these values are complete garbage */
+        DPRINTK_IOCTL("   HDIO_GETGEO: %x\n", HDIO_GETGEO);
+        if (!argument) return -EINVAL;
+        if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
+        if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
+        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+        if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
+        return 0;
+
+    case HDIO_GETGEO_BIG: 
+        /* note: these values are complete garbage */
+        DPRINTK_IOCTL("   HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
+        if (!argument) return -EINVAL;
+        if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
+        if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
+        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+        if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+        return 0;
+
+    case CDROMMULTISESSION:
+        DPRINTK("FIXME: support multisession CDs later\n");
+        for ( i = 0; i < sizeof(struct cdrom_multisession); i++ )
+            if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT;
+        return 0;
+
+    case SCSI_IOCTL_GET_BUS_NUMBER:
+        DPRINTK("FIXME: SCSI_IOCTL_GET_BUS_NUMBER ioctl in Xen blkdev");
+        return -ENOSYS;
+
+    default:
+        printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", command);
+        return -ENOSYS;
+    }
+    
+    return 0;
+}
+
+/* check media change: should probably do something here in some cases :-) */
+int xenolinux_block_check(kdev_t dev)
+{
+    DPRINTK("xenolinux_block_check\n");
+    return 0;
+}
+
+int xenolinux_block_revalidate(kdev_t dev)
+{
+    struct block_device *bd;
+    struct gendisk *gd;
+    xl_disk_t *disk;
+    unsigned long capacity;
+    int i, rc = 0;
+    
+    if ( (bd = bdget(dev)) == NULL )
+        return -EINVAL;
+
+    /*
+     * Update of partition info, and check of usage count, is protected
+     * by the per-block-device semaphore.
+     */
+    down(&bd->bd_sem);
+
+    if ( ((gd = get_gendisk(dev)) == NULL) ||
+         ((disk = xldev_to_xldisk(dev)) == NULL) ||
+         ((capacity = gd->part[MINOR(dev)].nr_sects) == 0) )
+    {
+        rc = -EINVAL;
+        goto out;
+    }
+
+    if ( disk->usage > 1 )
+    {
+        rc = -EBUSY;
+        goto out;
+    }
+
+    /* Only reread partition table if VBDs aren't mapped to partitions. */
+    if ( !(gd->flags[MINOR(dev) >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) )
+    {
+        for ( i = gd->max_p - 1; i >= 0; i-- )
+        {
+            invalidate_device(dev+i, 1);
+            gd->part[MINOR(dev+i)].start_sect = 0;
+            gd->part[MINOR(dev+i)].nr_sects   = 0;
+            gd->sizes[MINOR(dev+i)]           = 0;
+        }
+
+        grok_partitions(gd, MINOR(dev)>>gd->minor_shift, gd->max_p, capacity);
+    }
+
+ out:
+    up(&bd->bd_sem);
+    bdput(bd);
+    return rc;
+}
+
+
+/*
+ * hypervisor_request
+ *
+ * request block io 
+ * 
+ * id: for guest use only.
+ * operation: XEN_BLOCK_{READ,WRITE,PROBE,VBD*}
+ * buffer: buffer to read/write into. this should be a
+ *   virtual address in the guest os.
+ */
+static int hypervisor_request(unsigned long   id,
+                              int             operation,
+                              char *          buffer,
+                              unsigned long   sector_number,
+                              unsigned short  nr_sectors,
+                              kdev_t          device)
+{
+    unsigned long buffer_ma = phys_to_machine(virt_to_phys(buffer)); 
+    struct gendisk *gd;
+    blk_ring_req_entry_t *req;
+    struct buffer_head *bh;
+
+    if ( unlikely(nr_sectors >= (1<<9)) )
+        BUG();
+    if ( unlikely((buffer_ma & ((1<<9)-1)) != 0) )
+        BUG();
+
+    if ( unlikely(state == STATE_CLOSED) )
+        return 1;
+
+    switch ( operation )
+    {
+
+    case XEN_BLOCK_READ:
+    case XEN_BLOCK_WRITE:
+        gd = get_gendisk(device); 
+
+        /*
+         * Update the sector_number we'll pass down as appropriate; note that
+         * we could sanity check that resulting sector will be in this
+         * partition, but this will happen in xen anyhow.
+         */
+        sector_number += gd->part[MINOR(device)].start_sect;
+
+        /*
+         * If this unit doesn't consist of virtual (i.e., Xen-specified)
+         * partitions then we clear the partn bits from the device number.
+         */
+        if ( !(gd->flags[MINOR(device)>>gd->minor_shift] & 
+               GENHD_FL_VIRT_PARTNS) )
+            device &= ~(gd->max_p - 1);
+
+        if ( (sg_operation == operation) &&
+             (sg_dev == device) &&
+             (sg_next_sect == sector_number) )
+        {
+            req = &blk_ring->ring[MASK_BLK_IDX(req_prod-1)].req;
+            bh = (struct buffer_head *)id;
+            bh->b_reqnext = (struct buffer_head *)req->id;
+            req->id = id;
+            req->buffer_and_sects[req->nr_segments] = buffer_ma | nr_sectors;
+            if ( ++req->nr_segments < MAX_BLK_SEGS )
+                sg_next_sect += nr_sectors;
+            else
+                DISABLE_SCATTERGATHER();
+            return 0;
+        }
+        else if ( RING_PLUGGED )
+        {
+            return 1;
+        }
+        else
+        {
+            sg_operation = operation;
+            sg_dev       = device;
+            sg_next_sect = sector_number + nr_sectors;
+        }
+        break;
+
+    default:
+        panic("unknown op %d\n", operation);
+    }
+
+    /* Fill out a communications ring structure. */
+    req = &blk_ring->ring[MASK_BLK_IDX(req_prod)].req;
+    req->id            = id;
+    req->operation     = operation;
+    req->sector_number = (xen_sector_t)sector_number;
+    req->device        = device; 
+    req->nr_segments   = 1;
+    req->buffer_and_sects[0] = buffer_ma | nr_sectors;
+    req_prod++;
+
+    return 0;
+}
+
+
+/*
+ * do_xlblk_request
+ *  read a block; request is in a request queue
+ */
+void do_xlblk_request(request_queue_t *rq)
+{
+    struct request *req;
+    struct buffer_head *bh, *next_bh;
+    int rw, nsect, full, queued = 0;
+
+    DPRINTK("xlblk.c::do_xlblk_request\n"); 
+
+    while ( !rq->plugged && !list_empty(&rq->queue_head))
+    {
+        if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) 
+            goto out;
+  
+        DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
+                req, req->cmd, req->sector,
+                req->current_nr_sectors, req->nr_sectors, req->bh);
+
+        rw = req->cmd;
+        if ( rw == READA )
+            rw = READ;
+        if ( unlikely((rw != READ) && (rw != WRITE)) )
+            panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
+
+        req->errors = 0;
+
+        bh = req->bh;
+        while ( bh != NULL )
+        {
+            next_bh = bh->b_reqnext;
+            bh->b_reqnext = NULL;
+
+            full = hypervisor_request(
+                (unsigned long)bh,
+                (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
+                bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
+
+            if ( full )
+            { 
+                bh->b_reqnext = next_bh;
+                pending_queues[nr_pending++] = rq;
+                if ( unlikely(nr_pending >= MAX_PENDING) )
+                    BUG();
+                goto out; 
+            }
+
+            queued++;
+
+            /* Dequeue the buffer head from the request. */
+            nsect = bh->b_size >> 9;
+            bh = req->bh = next_bh;
+            
+            if ( bh != NULL )
+            {
+                /* There's another buffer head to do. Update the request. */
+                req->hard_sector += nsect;
+                req->hard_nr_sectors -= nsect;
+                req->sector = req->hard_sector;
+                req->nr_sectors = req->hard_nr_sectors;
+                req->current_nr_sectors = bh->b_size >> 9;
+                req->buffer = bh->b_data;
+            }
+            else
+            {
+                /* That was the last buffer head. Finalise the request. */
+                if ( unlikely(end_that_request_first(req, 1, "XenBlk")) )
+                    BUG();
+                blkdev_dequeue_request(req);
+                end_that_request_last(req);
+            }
+        }
+    }
+
+ out:
+    if ( queued != 0 ) signal_requests_to_xen();
+}
+
+
+static void kick_pending_request_queues(void)
+{
+    /* We kick pending request queues if the ring is reasonably empty. */
+    if ( (nr_pending != 0) && 
+         ((req_prod - resp_cons) < (BLK_RING_SIZE >> 1)) )
+    {
+        /* Attempt to drain the queue, but bail if the ring becomes full. */
+        while ( (nr_pending != 0) && !RING_PLUGGED )
+            do_xlblk_request(pending_queues[--nr_pending]);
+    }
+}
+
+
+static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+    BLK_RING_IDX i; 
+    unsigned long flags; 
+    struct buffer_head *bh, *next_bh;
+    
+    if ( unlikely(state == STATE_CLOSED) )
+        return;
+    
+    spin_lock_irqsave(&io_request_lock, flags);     
+
+    for ( i = resp_cons; i != blk_ring->resp_prod; i++ )
+    {
+        blk_ring_resp_entry_t *bret = &blk_ring->ring[MASK_BLK_IDX(i)].resp;
+        switch ( bret->operation )
+        {
+        case XEN_BLOCK_READ:
+        case XEN_BLOCK_WRITE:
+            if ( unlikely(bret->status != 0) )
+                DPRINTK("Bad return from blkdev data request: %lx\n",
+                        bret->status);
+            for ( bh = (struct buffer_head *)bret->id; 
+                  bh != NULL; 
+                  bh = next_bh )
+            {
+                next_bh = bh->b_reqnext;
+                bh->b_reqnext = NULL;
+                bh->b_end_io(bh, !bret->status);
+            }
+            break;
+     
+        default:
+            BUG();
+        }
+    }
+    
+    resp_cons = i;
+
+    kick_pending_request_queues();
+
+    spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+static void reset_xlblk_interface(void)
+{
+    block_io_op_t op; 
+
+    nr_pending = 0;
+
+    op.cmd = BLOCK_IO_OP_RESET;
+    if ( HYPERVISOR_block_io_op(&op) != 0 )
+        printk(KERN_ALERT "Possible blkdev trouble: couldn't reset ring\n");
+
+    op.cmd = BLOCK_IO_OP_RING_ADDRESS;
+    (void)HYPERVISOR_block_io_op(&op);
+
+    set_fixmap(FIX_BLKRING_BASE, op.u.ring_mfn << PAGE_SHIFT);
+    blk_ring = (blk_ring_t *)fix_to_virt(FIX_BLKRING_BASE);
+    blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
+
+    wmb();
+    state = STATE_ACTIVE;
+}
+
+
+int __init xlblk_init(void)
+{
+    int error; 
+
+    reset_xlblk_interface();
+
+    error = request_irq(XLBLK_RESPONSE_IRQ, xlblk_response_int, 
+                        SA_SAMPLE_RANDOM, "blkdev", NULL);
+    if ( error )
+    {
+        printk(KERN_ALERT "Could not allocate receive interrupt\n");
+        goto fail;
+    }
+
+    error = request_irq(XLBLK_UPDATE_IRQ, xlblk_update_int,
+                        SA_INTERRUPT, "blkdev", NULL);
+
+    if ( error )
+    {
+        printk(KERN_ALERT "Could not allocate block update interrupt\n");
+        goto fail;
+    }
+
+    (void)xlvbd_init();
+
+    return 0;
+
+ fail:
+    return error;
+}
+
+
+static void __exit xlblk_cleanup(void)
+{
+    xlvbd_cleanup();
+    free_irq(XLBLK_RESPONSE_IRQ, NULL);
+    free_irq(XLBLK_UPDATE_IRQ, NULL);
+}
+
+
+#ifdef MODULE
+module_init(xlblk_init);
+module_exit(xlblk_cleanup);
+#endif
+
+
+void blkdev_suspend(void)
+{
+    state = STATE_SUSPENDED;
+    wmb();
+
+    while ( resp_cons != blk_ring->req_prod )
+    {
+        barrier();
+        current->state = TASK_INTERRUPTIBLE;
+        schedule_timeout(1);
+    }
+
+    wmb();
+    state = STATE_CLOSED;
+    wmb();
+
+    clear_fixmap(FIX_BLKRING_BASE);
+}
+
+
+void blkdev_resume(void)
+{
+    reset_xlblk_interface();
+    spin_lock_irq(&io_request_lock);
+    kick_pending_request_queues();
+    spin_unlock_irq(&io_request_lock);
+}
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.h b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/block.h
new file mode 100644 (file)
index 0000000..ef8c241
--- /dev/null
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * block.h
+ * 
+ * Shared definitions between all levels of XenoLinux Virtual block devices.
+ */
+
+#ifndef __XENO_DRIVERS_BLOCK_H__
+#define __XENO_DRIVERS_BLOCK_H__
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/major.h>
+
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/hypervisor-ifs/vbd.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#if 0
+#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+#if 0
+#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
+#else
+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
+#endif
+
+/* Private gendisk->flags[] values. */
+#define GENHD_FL_XENO        2 /* Is unit a Xen block device?  */
+#define GENHD_FL_VIRT_PARTNS 4 /* Are unit partitions virtual? */
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'.
+ * They hang in an array off the gendisk structure. We may end up putting
+ * all kinds of interesting stuff here :-)
+ */
+typedef struct xl_disk {
+    int usage;
+} xl_disk_t;
+
+extern int xenolinux_control_msg(int operration, char *buffer, int size);
+extern int xenolinux_block_open(struct inode *inode, struct file *filep);
+extern int xenolinux_block_release(struct inode *inode, struct file *filep);
+extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+                                 unsigned command, unsigned long argument);
+extern int xenolinux_block_check(kdev_t dev);
+extern int xenolinux_block_revalidate(kdev_t dev);
+extern void do_xlblk_request (request_queue_t *rq); 
+
+extern void xlvbd_update_vbds(void);
+
+static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
+{
+    struct gendisk *gd = get_gendisk(xldev);
+    
+    if ( gd == NULL ) 
+        return NULL;
+    
+    return (xl_disk_t *)gd->real_devices + 
+        (MINOR(xldev) >> gd->minor_shift);
+}
+
+
+/* Virtual block-device subsystem. */
+extern int  xlvbd_init(void);
+extern void xlvbd_cleanup(void); 
+
+#endif /* __XENO_DRIVERS_BLOCK_H__ */
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/vbd.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/vbd.c
new file mode 100644 (file)
index 0000000..e3473da
--- /dev/null
@@ -0,0 +1,561 @@
+/******************************************************************************
+ * vbd.c
+ * 
+ * Xenolinux virtual block-device driver (xvd).
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ */
+
+#include "block.h"
+#include <linux/blk.h>
+
+/*
+ * For convenience we distinguish between ide, scsi and 'other' (i.e.
+ * potentially combinations of the two) in the naming scheme and in a few 
+ * other places (like default readahead, etc).
+ */
+#define XLIDE_MAJOR_NAME  "hd"
+#define XLSCSI_MAJOR_NAME "sd"
+#define XLVBD_MAJOR_NAME "xvd"
+
+#define XLIDE_DEVS_PER_MAJOR   2
+#define XLSCSI_DEVS_PER_MAJOR 16
+#define XLVBD_DEVS_PER_MAJOR  16
+
+#define XLIDE_PARTN_SHIFT  6    /* amount to shift minor to get 'real' minor */
+#define XLIDE_MAX_PART    (1 << XLIDE_PARTN_SHIFT)     /* minors per ide vbd */
+
+#define XLSCSI_PARTN_SHIFT 4    /* amount to shift minor to get 'real' minor */
+#define XLSCSI_MAX_PART   (1 << XLSCSI_PARTN_SHIFT)   /* minors per scsi vbd */
+
+#define XLVBD_PARTN_SHIFT  4    /* amount to shift minor to get 'real' minor */
+#define XLVBD_MAX_PART    (1 << XLVBD_PARTN_SHIFT) /* minors per 'other' vbd */
+
+/* The below are for the generic drivers/block/ll_rw_block.c code. */
+static int xlide_blksize_size[256];
+static int xlide_hardsect_size[256];
+static int xlide_max_sectors[256];
+static int xlscsi_blksize_size[256];
+static int xlscsi_hardsect_size[256];
+static int xlscsi_max_sectors[256];
+static int xlvbd_blksize_size[256];
+static int xlvbd_hardsect_size[256];
+static int xlvbd_max_sectors[256];
+
+/* Information from Xen about our VBDs. */
+#define MAX_VBDS 64
+static int nr_vbds;
+static xen_disk_t *vbd_info;
+
+static struct block_device_operations xlvbd_block_fops = 
+{
+    open:               xenolinux_block_open,
+    release:            xenolinux_block_release,
+    ioctl:              xenolinux_block_ioctl,
+    check_media_change: xenolinux_block_check,
+    revalidate:         xenolinux_block_revalidate,
+};
+
+static int xlvbd_get_vbd_info(xen_disk_t *disk_info)
+{
+    int error;
+    block_io_op_t op; 
+
+    /* Probe for disk information. */
+    memset(&op, 0, sizeof(op)); 
+    op.cmd = BLOCK_IO_OP_VBD_PROBE; 
+    op.u.probe_params.domain    = 0; 
+    op.u.probe_params.xdi.max   = MAX_VBDS;
+    op.u.probe_params.xdi.disks = disk_info;
+    op.u.probe_params.xdi.count = 0;
+
+    if ( (error = HYPERVISOR_block_io_op(&op)) != 0 )
+    {
+        printk(KERN_ALERT "Could not probe disks (%d)\n", error);
+        return -1;
+    }
+
+    return op.u.probe_params.xdi.count;
+}
+
+/*
+ * xlvbd_init_device - initialise a VBD device
+ * @disk:              a xen_disk_t describing the VBD
+ *
+ * Takes a xen_disk_t * that describes a VBD the domain has access to.
+ * Performs appropriate initialisation and registration of the device.
+ *
+ * Care needs to be taken when making re-entrant calls to ensure that
+ * corruption does not occur.  Also, devices that are in use should not have
+ * their details updated.  This is the caller's responsibility.
+ */
+static int xlvbd_init_device(xen_disk_t *xd)
+{
+    int device = xd->device;
+    int major  = MAJOR(device); 
+    int minor  = MINOR(device);
+    int is_ide = IDE_DISK_MAJOR(major);  /* is this an ide device? */
+    int is_scsi= SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
+    char *major_name;
+    struct gendisk *gd;
+    struct block_device *bd;
+    xl_disk_t *disk;
+    int i, rc = 0, max_part, partno;
+    unsigned long capacity;
+
+    unsigned char buf[64];
+
+    if ( (bd = bdget(device)) == NULL )
+        return -1;
+
+    /*
+     * Update of partition info, and check of usage count, is protected
+     * by the per-block-device semaphore.
+     */
+    down(&bd->bd_sem);
+
+    if ( ((disk = xldev_to_xldisk(device)) != NULL) && (disk->usage != 0) )
+    {
+        printk(KERN_ALERT "VBD update failed - in use [dev=%x]\n", device);
+        rc = -1;
+        goto out;
+    }
+
+    if ( is_ide ) {
+
+       major_name = XLIDE_MAJOR_NAME; 
+       max_part   = XLIDE_MAX_PART;
+
+    } else if ( is_scsi ) {
+
+       major_name = XLSCSI_MAJOR_NAME;
+       max_part   = XLSCSI_MAX_PART;
+
+    } else if (XD_VIRTUAL(xd->info)) {
+
+       major_name = XLVBD_MAJOR_NAME;
+       max_part   = XLVBD_MAX_PART;
+
+    } else { 
+
+        /* SMH: hmm - probably a CCISS driver or sim; assume CCISS for now */
+       printk(KERN_ALERT "Assuming device %02x:%02x is CCISS/SCSI\n", 
+              major, minor);
+       is_scsi    = 1; 
+       major_name = "cciss"; 
+       max_part   = XLSCSI_MAX_PART;
+
+    }
+    
+    partno = minor & (max_part - 1); 
+    
+    if ( (gd = get_gendisk(device)) == NULL )
+    {
+        rc = register_blkdev(major, major_name, &xlvbd_block_fops);
+        if ( rc < 0 )
+        {
+            printk(KERN_ALERT "XL VBD: can't get major %d\n", major);
+            goto out;
+        }
+
+        if ( is_ide )
+        { 
+            blksize_size[major]  = xlide_blksize_size;
+            hardsect_size[major] = xlide_hardsect_size;
+            max_sectors[major]   = xlide_max_sectors;
+            read_ahead[major]    = 8; /* from drivers/ide/ide-probe.c */
+        } 
+        else if ( is_scsi )
+        { 
+            blksize_size[major]  = xlscsi_blksize_size;
+            hardsect_size[major] = xlscsi_hardsect_size;
+            max_sectors[major]   = xlscsi_max_sectors;
+            read_ahead[major]    = 0; /* XXX 8; -- guessing */
+        }
+        else
+        { 
+            blksize_size[major]  = xlvbd_blksize_size;
+            hardsect_size[major] = xlvbd_hardsect_size;
+            max_sectors[major]   = xlvbd_max_sectors;
+            read_ahead[major]    = 8;
+        }
+
+        blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
+
+        /*
+         * Turn off barking 'headactive' mode. We dequeue buffer heads as
+         * soon as we pass them down to Xen.
+         */
+        blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
+
+        /* Construct an appropriate gendisk structure. */
+        gd             = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+        gd->major      = major;
+        gd->major_name = major_name; 
+    
+        gd->max_p      = max_part; 
+        if ( is_ide )
+        { 
+            gd->minor_shift  = XLIDE_PARTN_SHIFT; 
+            gd->nr_real      = XLIDE_DEVS_PER_MAJOR; 
+        } 
+        else if ( is_scsi )
+        { 
+            gd->minor_shift  = XLSCSI_PARTN_SHIFT; 
+            gd->nr_real      = XLSCSI_DEVS_PER_MAJOR; 
+        }
+        else
+        { 
+            gd->minor_shift  = XLVBD_PARTN_SHIFT; 
+            gd->nr_real      = XLVBD_DEVS_PER_MAJOR; 
+        }
+
+        /* 
+        ** The sizes[] and part[] arrays hold the sizes and other 
+        ** information about every partition with this 'major' (i.e. 
+        ** every disk sharing the 8 bit prefix * max partns per disk) 
+        */
+        gd->sizes = kmalloc(max_part*gd->nr_real*sizeof(int), GFP_KERNEL);
+        gd->part  = kmalloc(max_part*gd->nr_real*sizeof(struct hd_struct), 
+                            GFP_KERNEL);
+        memset(gd->sizes, 0, max_part * gd->nr_real * sizeof(int));
+        memset(gd->part,  0, max_part * gd->nr_real 
+               * sizeof(struct hd_struct));
+
+
+        gd->real_devices = kmalloc(gd->nr_real * sizeof(xl_disk_t), 
+                                   GFP_KERNEL);
+        memset(gd->real_devices, 0, gd->nr_real * sizeof(xl_disk_t));
+
+        gd->next   = NULL;            
+        gd->fops   = &xlvbd_block_fops;
+
+        gd->de_arr = kmalloc(gd->nr_real * sizeof(*gd->de_arr), 
+                             GFP_KERNEL);
+        gd->flags  = kmalloc(gd->nr_real * sizeof(*gd->flags), GFP_KERNEL);
+    
+        memset(gd->de_arr, 0, gd->nr_real * sizeof(*gd->de_arr));
+        memset(gd->flags, 0, gd->nr_real *  sizeof(*gd->flags));
+
+        add_gendisk(gd);
+
+        blk_size[major] = gd->sizes;
+    }
+
+    if ( XD_READONLY(xd->info) )
+        set_device_ro(device, 1); 
+
+    gd->flags[minor >> gd->minor_shift] |= GENHD_FL_XENO;
+
+    /* NB. Linux 2.4 only handles 32-bit sector offsets and capacities. */
+    capacity = (unsigned long)xd->capacity;
+
+    if ( partno != 0 )
+    {
+        /*
+         * If this was previously set up as a real disc we will have set 
+         * up partition-table information. Virtual partitions override 
+         * 'real' partitions, and the two cannot coexist on a device.
+         */
+        if ( !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) &&
+             (gd->sizes[minor & ~(max_part-1)] != 0) )
+        {
+            /*
+             * Any non-zero sub-partition entries must be cleaned out before
+             * installing 'virtual' partition entries. The two types cannot
+             * coexist, and virtual partitions are favoured.
+             */
+            kdev_t dev = device & ~(max_part-1);
+            for ( i = max_part - 1; i > 0; i-- )
+            {
+                invalidate_device(dev+i, 1);
+                gd->part[MINOR(dev+i)].start_sect = 0;
+                gd->part[MINOR(dev+i)].nr_sects   = 0;
+                gd->sizes[MINOR(dev+i)]           = 0;
+            }
+            printk(KERN_ALERT
+                   "Virtual partitions found for /dev/%s - ignoring any "
+                   "real partition information we may have found.\n",
+                   disk_name(gd, MINOR(device), buf));
+        }
+
+        /* Need to skankily setup 'partition' information */
+        gd->part[minor].start_sect = 0; 
+        gd->part[minor].nr_sects   = capacity; 
+        gd->sizes[minor]           = capacity; 
+
+        gd->flags[minor >> gd->minor_shift] |= GENHD_FL_VIRT_PARTNS;
+    }
+    else
+    {
+        gd->part[minor].nr_sects = capacity;
+        gd->sizes[minor] = capacity>>(BLOCK_SIZE_BITS-9);
+        
+        /* Some final fix-ups depending on the device type */
+        switch ( XD_TYPE(xd->info) )
+        { 
+        case XD_TYPE_CDROM:
+        case XD_TYPE_FLOPPY: 
+        case XD_TYPE_TAPE:
+            gd->flags[minor >> gd->minor_shift] |= GENHD_FL_REMOVABLE; 
+            printk(KERN_ALERT 
+                   "Skipping partition check on %s /dev/%s\n", 
+                   XD_TYPE(xd->info)==XD_TYPE_CDROM ? "cdrom" : 
+                   (XD_TYPE(xd->info)==XD_TYPE_TAPE ? "tape" : 
+                    "floppy"), disk_name(gd, MINOR(device), buf)); 
+            break; 
+
+        case XD_TYPE_DISK:
+            /* Only check partitions on real discs (not virtual!). */
+            if ( gd->flags[minor>>gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
+            {
+                printk(KERN_ALERT
+                       "Skipping partition check on virtual /dev/%s\n",
+                       disk_name(gd, MINOR(device), buf));
+                break;
+            }
+            register_disk(gd, device, gd->max_p, &xlvbd_block_fops, capacity);
+            break; 
+
+        default:
+            printk(KERN_ALERT "XenoLinux: unknown device type %d\n", 
+                   XD_TYPE(xd->info)); 
+            break; 
+        }
+    }
+
+ out:
+    up(&bd->bd_sem);
+    bdput(bd);    
+    return rc;
+}
+
+
+/*
+ * xlvbd_remove_device - remove a device node if possible
+ * @device:       numeric device ID
+ *
+ * Updates the gendisk structure and invalidates devices.
+ *
+ * This is OK for now but in future, should perhaps consider where this should
+ * deallocate gendisks / unregister devices.
+ */
+static int xlvbd_remove_device(int device)
+{
+    int i, rc = 0, minor = MINOR(device);
+    struct gendisk *gd;
+    struct block_device *bd;
+    xl_disk_t *disk = NULL;
+
+    if ( (bd = bdget(device)) == NULL )
+        return -1;
+
+    /*
+     * Update of partition info, and check of usage count, is protected
+     * by the per-block-device semaphore.
+     */
+    down(&bd->bd_sem);
+
+    if ( ((gd = get_gendisk(device)) == NULL) ||
+         ((disk = xldev_to_xldisk(device)) == NULL) )
+        BUG();
+
+    if ( disk->usage != 0 )
+    {
+        printk(KERN_ALERT "VBD removal failed - in use [dev=%x]\n", device);
+        rc = -1;
+        goto out;
+    }
+    if ( (minor & (gd->max_p-1)) != 0 )
+    {
+        /* 1: The VBD is mapped to a partition rather than a whole unit. */
+        invalidate_device(device, 1);
+       gd->part[minor].start_sect = 0;
+        gd->part[minor].nr_sects   = 0;
+        gd->sizes[minor]           = 0;
+
+        /* Clear the consists-of-virtual-partitions flag if possible. */
+        gd->flags[minor >> gd->minor_shift] &= ~GENHD_FL_VIRT_PARTNS;
+        for ( i = 1; i < gd->max_p; i++ )
+            if ( gd->sizes[(minor & ~(gd->max_p-1)) + i] != 0 )
+                gd->flags[minor >> gd->minor_shift] |= GENHD_FL_VIRT_PARTNS;
+
+        /*
+         * If all virtual partitions are now gone, and a 'whole unit' VBD is
+         * present, then we can try to grok the unit's real partition table.
+         */
+        if ( !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) &&
+             (gd->sizes[minor & ~(gd->max_p-1)] != 0) &&
+             !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE) )
+        {
+            register_disk(gd,
+                          device&~(gd->max_p-1), 
+                          gd->max_p, 
+                          &xlvbd_block_fops,
+                          gd->part[minor&~(gd->max_p-1)].nr_sects);
+        }
+    }
+    else
+    {
+        /*
+         * 2: The VBD is mapped to an entire 'unit'. Clear all partitions.
+         * NB. The partition entries are only cleared if there are no VBDs
+         * mapped to individual partitions on this unit.
+         */
+        i = gd->max_p - 1; /* Default: clear subpartitions as well. */
+        if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
+            i = 0; /* 'Virtual' mode: only clear the 'whole unit' entry. */
+        while ( i >= 0 )
+        {
+            invalidate_device(device+i, 1);
+            gd->part[minor+i].start_sect = 0;
+            gd->part[minor+i].nr_sects   = 0;
+            gd->sizes[minor+i]           = 0;
+            i--;
+        }
+    }
+
+ out:
+    up(&bd->bd_sem);
+    bdput(bd);
+    return rc;
+}
+
+/*
+ * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
+ * state. The VBDs need to be updated in this way when the domain is
+ * initialised and also each time we receive an XLBLK_UPDATE event.
+ */
+void xlvbd_update_vbds(void)
+{
+    int i, j, k, old_nr, new_nr;
+    xen_disk_t *old_info, *new_info, *merged_info;
+
+    old_info = vbd_info;
+    old_nr   = nr_vbds;
+
+    new_info = kmalloc(MAX_VBDS * sizeof(xen_disk_t), GFP_KERNEL);
+    if ( unlikely(new_nr = xlvbd_get_vbd_info(new_info)) < 0 )
+    {
+        kfree(new_info);
+        return;
+    }
+
+    /*
+     * Final list maximum size is old list + new list. This occurs only when
+     * old list and new list do not overlap at all, and we cannot yet destroy
+     * VBDs in the old list because the usage counts are busy.
+     */
+    merged_info = kmalloc((old_nr + new_nr) * sizeof(xen_disk_t), GFP_KERNEL);
+
+    /* @i tracks old list; @j tracks new list; @k tracks merged list. */
+    i = j = k = 0;
+
+    while ( (i < old_nr) && (j < new_nr) )
+    {
+        if ( old_info[i].device < new_info[j].device )
+        {
+            if ( xlvbd_remove_device(old_info[i].device) != 0 )
+                memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
+            i++;
+        }
+        else if ( old_info[i].device > new_info[j].device )
+        {
+            if ( xlvbd_init_device(&new_info[j]) == 0 )
+                memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
+            j++;
+        }
+        else
+        {
+            if ( ((old_info[i].capacity == new_info[j].capacity) &&
+                  (old_info[i].info == new_info[j].info)) ||
+                 (xlvbd_remove_device(old_info[i].device) != 0) )
+                memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
+            else if ( xlvbd_init_device(&new_info[j]) == 0 )
+                memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
+            i++; j++;
+        }
+    }
+
+    for ( ; i < old_nr; i++ )
+    {
+        if ( xlvbd_remove_device(old_info[i].device) != 0 )
+            memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
+    }
+
+    for ( ; j < new_nr; j++ )
+    {
+        if ( xlvbd_init_device(&new_info[j]) == 0 )
+            memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
+    }
+
+    vbd_info = merged_info;
+    nr_vbds  = k;
+
+    kfree(old_info);
+    kfree(new_info);
+}
+
+
+/*
+ * Set up all the linux device goop for the virtual block devices (vbd's) that 
+ * xen tells us about. Note that although from xen's pov VBDs are addressed 
+ * simply an opaque 16-bit device number, the domain creation tools 
+ * conventionally allocate these numbers to correspond to those used by 'real' 
+ * linux -- this is just for convenience as it means e.g. that the same 
+ * /etc/fstab can be used when booting with or without xen.
+ */
+int __init xlvbd_init(void)
+{
+    int i;
+    
+    /*
+     * If compiled as a module, we don't support unloading yet. We therefore 
+     * permanently increment the reference count to disallow it.
+     */
+    SET_MODULE_OWNER(&xlvbd_block_fops);
+    MOD_INC_USE_COUNT;
+
+    /* Initialize the global arrays. */
+    for ( i = 0; i < 256; i++ ) 
+    {
+        /* from the generic ide code (drivers/ide/ide-probe.c, etc) */
+        xlide_blksize_size[i]  = 1024;
+        xlide_hardsect_size[i] = 512;
+        xlide_max_sectors[i]   = 128;  /* 'hwif->rqsize' if we knew it */
+
+        /* from the generic scsi disk code (drivers/scsi/sd.c) */
+        xlscsi_blksize_size[i]  = 1024; /* XXX 512; */
+        xlscsi_hardsect_size[i] = 512;
+        xlscsi_max_sectors[i]   = 128*8; /* XXX 128; */
+
+        /* we don't really know what to set these too since it depends */
+        xlvbd_blksize_size[i]  = 512;
+        xlvbd_hardsect_size[i] = 512;
+        xlvbd_max_sectors[i]   = 128;
+    }
+
+    vbd_info = kmalloc(MAX_VBDS * sizeof(xen_disk_t), GFP_KERNEL);
+    nr_vbds  = xlvbd_get_vbd_info(vbd_info);
+
+    if ( nr_vbds < 0 )
+    {
+        kfree(vbd_info);
+        vbd_info = NULL;
+        nr_vbds  = 0;
+    }
+    else
+    {
+        for ( i = 0; i < nr_vbds; i++ )
+            xlvbd_init_device(&vbd_info[i]);
+    }
+
+    return 0;
+}
+
+
+#ifdef MODULE
+module_init(xlvbd_init);
+#endif
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.c
deleted file mode 100644 (file)
index dac8c26..0000000
+++ /dev/null
@@ -1,621 +0,0 @@
-/******************************************************************************
- * xl_block.c
- * 
- * Xenolinux virtual block-device driver.
- * 
- * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
- * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
- */
-
-#include "xl_block.h"
-#include <linux/blk.h>
-#include <linux/cdrom.h>
-#include <linux/tqueue.h>
-#include <linux/sched.h>
-#include <scsi/scsi.h>
-
-#include <linux/interrupt.h>
-
-typedef unsigned char byte; /* from linux/ide.h */
-
-#define XLBLK_RESPONSE_IRQ HYPEREVENT_IRQ(_EVENT_BLKDEV)
-#define XLBLK_UPDATE_IRQ   HYPEREVENT_IRQ(_EVENT_VBD_UPD)
-#define DEBUG_IRQ          HYPEREVENT_IRQ(_EVENT_DEBUG)
-
-#define STATE_ACTIVE    0
-#define STATE_SUSPENDED 1
-#define STATE_CLOSED    2
-static unsigned int state = STATE_SUSPENDED;
-
-static blk_ring_t *blk_ring;
-static BLK_RING_IDX resp_cons; /* Response consumer for comms ring. */
-static BLK_RING_IDX req_prod;  /* Private request producer.         */
-
-/* We plug the I/O ring if the driver is suspended or if the ring is full. */
-#define RING_PLUGGED (((req_prod - resp_cons) == BLK_RING_SIZE) || \
-                      (state != STATE_ACTIVE))
-
-
-/*
- * Request queues with outstanding work, but ring is currently full.
- * We need no special lock here, as we always access this with the
- * io_request_lock held. We only need a small maximum list.
- */
-#define MAX_PENDING 8
-static request_queue_t *pending_queues[MAX_PENDING];
-static int nr_pending;
-
-static kdev_t        sg_dev;
-static int           sg_operation = -1;
-static unsigned long sg_next_sect;
-#define DISABLE_SCATTERGATHER() (sg_operation = -1)
-
-static inline void signal_requests_to_xen(void)
-{
-    block_io_op_t op; 
-
-    DISABLE_SCATTERGATHER();
-    blk_ring->req_prod = req_prod;
-
-    op.cmd = BLOCK_IO_OP_SIGNAL; 
-    HYPERVISOR_block_io_op(&op);
-    return;
-}
-
-
-/*
- * xlblk_update_int/update-vbds_task - handle VBD update events from Xen
- * 
- * Schedule a task for keventd to run, which will update the VBDs and perform 
- * the corresponding updates to our view of VBD state, so the XenoLinux will 
- * respond to changes / additions / deletions to the set of VBDs automatically.
- */
-static struct tq_struct update_tq;
-static void update_vbds_task(void *unused)
-{ 
-    xlvbd_update_vbds();
-}
-static void xlblk_update_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
-    update_tq.routine = update_vbds_task;
-    schedule_task(&update_tq);
-}
-
-
-int xenolinux_block_open(struct inode *inode, struct file *filep)
-{
-    short xldev = inode->i_rdev; 
-    struct gendisk *gd = get_gendisk(xldev);
-    xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
-    short minor = MINOR(xldev); 
-
-    if ( gd->part[minor].nr_sects == 0 )
-    { 
-        /*
-         * Device either doesn't exist, or has zero capacity; we use a few
-         * cheesy heuristics to return the relevant error code
-         */
-        if ( (gd->sizes[minor >> gd->minor_shift] != 0) ||
-             ((minor & (gd->max_p - 1)) != 0) )
-        { 
-            /*
-             * We have a real device, but no such partition, or we just have a
-             * partition number so guess this is the problem.
-             */
-            return -ENXIO;     /* no such device or address */
-        }
-        else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE )
-        {
-            /* This is a removable device => assume that media is missing. */ 
-            return -ENOMEDIUM; /* media not present (this is a guess) */
-        } 
-        else
-        { 
-            /* Just go for the general 'no such device' error. */
-            return -ENODEV;    /* no such device */
-        }
-    }
-    
-    /* Update of usage count is protected by per-device semaphore. */
-    disk->usage++;
-
-    return 0;
-}
-
-
-int xenolinux_block_release(struct inode *inode, struct file *filep)
-{
-    xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
-
-    /*
-     * When usage drops to zero it may allow more VBD updates to occur.
-     * Update of usage count is protected by a per-device semaphore.
-     */
-    if ( --disk->usage == 0 )
-    {
-        update_tq.routine = update_vbds_task;
-        schedule_task(&update_tq);
-    }
-
-    return 0;
-}
-
-
-int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
-                          unsigned command, unsigned long argument)
-{
-    kdev_t dev = inode->i_rdev;
-    struct hd_geometry *geo = (struct hd_geometry *)argument;
-    struct gendisk *gd;     
-    struct hd_struct *part; 
-    int i;
-
-    /* NB. No need to check permissions. That is done for us. */
-    
-    DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
-                  command, (long) argument, dev); 
-  
-    gd = get_gendisk(dev);
-    part = &gd->part[MINOR(dev)]; 
-
-    switch ( command )
-    {
-    case BLKGETSIZE:
-        DPRINTK_IOCTL("   BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects); 
-        return put_user(part->nr_sects, (unsigned long *) argument);
-
-    case BLKGETSIZE64:
-        DPRINTK_IOCTL("   BLKGETSIZE64: %x %llx\n", BLKGETSIZE64,
-                      (u64)part->nr_sects * 512);
-        return put_user((u64)part->nr_sects * 512, (u64 *) argument);
-
-    case BLKRRPART:                               /* re-read partition table */
-        DPRINTK_IOCTL("   BLKRRPART: %x\n", BLKRRPART);
-        return xenolinux_block_revalidate(dev);
-
-    case BLKSSZGET:
-        return hardsect_size[MAJOR(dev)][MINOR(dev)]; 
-
-    case BLKBSZGET:                                        /* get block size */
-        DPRINTK_IOCTL("   BLKBSZGET: %x\n", BLKBSZGET);
-        break;
-
-    case BLKBSZSET:                                        /* set block size */
-        DPRINTK_IOCTL("   BLKBSZSET: %x\n", BLKBSZSET);
-        break;
-
-    case BLKRASET:                                         /* set read-ahead */
-        DPRINTK_IOCTL("   BLKRASET: %x\n", BLKRASET);
-        break;
-
-    case BLKRAGET:                                         /* get read-ahead */
-        DPRINTK_IOCTL("   BLKRAFET: %x\n", BLKRAGET);
-        break;
-
-    case HDIO_GETGEO:
-        /* note: these values are complete garbage */
-        DPRINTK_IOCTL("   HDIO_GETGEO: %x\n", HDIO_GETGEO);
-        if (!argument) return -EINVAL;
-        if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
-        if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
-        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
-        if (put_user(0x106, (unsigned short *)&geo->cylinders)) return -EFAULT;
-        return 0;
-
-    case HDIO_GETGEO_BIG: 
-        /* note: these values are complete garbage */
-        DPRINTK_IOCTL("   HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
-        if (!argument) return -EINVAL;
-        if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
-        if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
-        if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
-        if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
-        return 0;
-
-    case CDROMMULTISESSION:
-        DPRINTK("FIXME: support multisession CDs later\n");
-        for ( i = 0; i < sizeof(struct cdrom_multisession); i++ )
-            if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT;
-        return 0;
-
-    case SCSI_IOCTL_GET_BUS_NUMBER:
-        DPRINTK("FIXME: SCSI_IOCTL_GET_BUS_NUMBER ioctl in xl_block");
-        return -ENOSYS;
-
-    default:
-        printk(KERN_ALERT "ioctl %08x not supported by xl_block\n", command);
-        return -ENOSYS;
-    }
-    
-    return 0;
-}
-
-/* check media change: should probably do something here in some cases :-) */
-int xenolinux_block_check(kdev_t dev)
-{
-    DPRINTK("xenolinux_block_check\n");
-    return 0;
-}
-
-int xenolinux_block_revalidate(kdev_t dev)
-{
-    struct block_device *bd;
-    struct gendisk *gd;
-    xl_disk_t *disk;
-    unsigned long capacity;
-    int i, rc = 0;
-    
-    if ( (bd = bdget(dev)) == NULL )
-        return -EINVAL;
-
-    /*
-     * Update of partition info, and check of usage count, is protected
-     * by the per-block-device semaphore.
-     */
-    down(&bd->bd_sem);
-
-    if ( ((gd = get_gendisk(dev)) == NULL) ||
-         ((disk = xldev_to_xldisk(dev)) == NULL) ||
-         ((capacity = gd->part[MINOR(dev)].nr_sects) == 0) )
-    {
-        rc = -EINVAL;
-        goto out;
-    }
-
-    if ( disk->usage > 1 )
-    {
-        rc = -EBUSY;
-        goto out;
-    }
-
-    /* Only reread partition table if VBDs aren't mapped to partitions. */
-    if ( !(gd->flags[MINOR(dev) >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) )
-    {
-        for ( i = gd->max_p - 1; i >= 0; i-- )
-        {
-            invalidate_device(dev+i, 1);
-            gd->part[MINOR(dev+i)].start_sect = 0;
-            gd->part[MINOR(dev+i)].nr_sects   = 0;
-            gd->sizes[MINOR(dev+i)]           = 0;
-        }
-
-        grok_partitions(gd, MINOR(dev)>>gd->minor_shift, gd->max_p, capacity);
-    }
-
- out:
-    up(&bd->bd_sem);
-    bdput(bd);
-    return rc;
-}
-
-
-/*
- * hypervisor_request
- *
- * request block io 
- * 
- * id: for guest use only.
- * operation: XEN_BLOCK_{READ,WRITE,PROBE,VBD*}
- * buffer: buffer to read/write into. this should be a
- *   virtual address in the guest os.
- */
-static int hypervisor_request(unsigned long   id,
-                              int             operation,
-                              char *          buffer,
-                              unsigned long   sector_number,
-                              unsigned short  nr_sectors,
-                              kdev_t          device)
-{
-    unsigned long buffer_ma = phys_to_machine(virt_to_phys(buffer)); 
-    struct gendisk *gd;
-    blk_ring_req_entry_t *req;
-    struct buffer_head *bh;
-
-    if ( unlikely(nr_sectors >= (1<<9)) )
-        BUG();
-    if ( unlikely((buffer_ma & ((1<<9)-1)) != 0) )
-        BUG();
-
-    if ( unlikely(state == STATE_CLOSED) )
-        return 1;
-
-    switch ( operation )
-    {
-
-    case XEN_BLOCK_READ:
-    case XEN_BLOCK_WRITE:
-        gd = get_gendisk(device); 
-
-        /*
-         * Update the sector_number we'll pass down as appropriate; note that
-         * we could sanity check that resulting sector will be in this
-         * partition, but this will happen in xen anyhow.
-         */
-        sector_number += gd->part[MINOR(device)].start_sect;
-
-        /*
-         * If this unit doesn't consist of virtual (i.e., Xen-specified)
-         * partitions then we clear the partn bits from the device number.
-         */
-        if ( !(gd->flags[MINOR(device)>>gd->minor_shift] & 
-               GENHD_FL_VIRT_PARTNS) )
-            device &= ~(gd->max_p - 1);
-
-        if ( (sg_operation == operation) &&
-             (sg_dev == device) &&
-             (sg_next_sect == sector_number) )
-        {
-            req = &blk_ring->ring[MASK_BLK_IDX(req_prod-1)].req;
-            bh = (struct buffer_head *)id;
-            bh->b_reqnext = (struct buffer_head *)req->id;
-            req->id = id;
-            req->buffer_and_sects[req->nr_segments] = buffer_ma | nr_sectors;
-            if ( ++req->nr_segments < MAX_BLK_SEGS )
-                sg_next_sect += nr_sectors;
-            else
-                DISABLE_SCATTERGATHER();
-            return 0;
-        }
-        else if ( RING_PLUGGED )
-        {
-            return 1;
-        }
-        else
-        {
-            sg_operation = operation;
-            sg_dev       = device;
-            sg_next_sect = sector_number + nr_sectors;
-        }
-        break;
-
-    default:
-        panic("unknown op %d\n", operation);
-    }
-
-    /* Fill out a communications ring structure. */
-    req = &blk_ring->ring[MASK_BLK_IDX(req_prod)].req;
-    req->id            = id;
-    req->operation     = operation;
-    req->sector_number = (xen_sector_t)sector_number;
-    req->device        = device; 
-    req->nr_segments   = 1;
-    req->buffer_and_sects[0] = buffer_ma | nr_sectors;
-    req_prod++;
-
-    return 0;
-}
-
-
-/*
- * do_xlblk_request
- *  read a block; request is in a request queue
- */
-void do_xlblk_request(request_queue_t *rq)
-{
-    struct request *req;
-    struct buffer_head *bh, *next_bh;
-    int rw, nsect, full, queued = 0;
-
-    DPRINTK("xlblk.c::do_xlblk_request\n"); 
-
-    while ( !rq->plugged && !list_empty(&rq->queue_head))
-    {
-        if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) 
-            goto out;
-  
-        DPRINTK("do_xlblk_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
-                req, req->cmd, req->sector,
-                req->current_nr_sectors, req->nr_sectors, req->bh);
-
-        rw = req->cmd;
-        if ( rw == READA )
-            rw = READ;
-        if ( unlikely((rw != READ) && (rw != WRITE)) )
-            panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw);
-
-        req->errors = 0;
-
-        bh = req->bh;
-        while ( bh != NULL )
-        {
-            next_bh = bh->b_reqnext;
-            bh->b_reqnext = NULL;
-
-            full = hypervisor_request(
-                (unsigned long)bh,
-                (rw == READ) ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
-                bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
-
-            if ( full )
-            { 
-                bh->b_reqnext = next_bh;
-                pending_queues[nr_pending++] = rq;
-                if ( unlikely(nr_pending >= MAX_PENDING) )
-                    BUG();
-                goto out; 
-            }
-
-            queued++;
-
-            /* Dequeue the buffer head from the request. */
-            nsect = bh->b_size >> 9;
-            bh = req->bh = next_bh;
-            
-            if ( bh != NULL )
-            {
-                /* There's another buffer head to do. Update the request. */
-                req->hard_sector += nsect;
-                req->hard_nr_sectors -= nsect;
-                req->sector = req->hard_sector;
-                req->nr_sectors = req->hard_nr_sectors;
-                req->current_nr_sectors = bh->b_size >> 9;
-                req->buffer = bh->b_data;
-            }
-            else
-            {
-                /* That was the last buffer head. Finalise the request. */
-                if ( unlikely(end_that_request_first(req, 1, "XenBlk")) )
-                    BUG();
-                blkdev_dequeue_request(req);
-                end_that_request_last(req);
-            }
-        }
-    }
-
- out:
-    if ( queued != 0 ) signal_requests_to_xen();
-}
-
-
-static void kick_pending_request_queues(void)
-{
-    /* We kick pending request queues if the ring is reasonably empty. */
-    if ( (nr_pending != 0) && 
-         ((req_prod - resp_cons) < (BLK_RING_SIZE >> 1)) )
-    {
-        /* Attempt to drain the queue, but bail if the ring becomes full. */
-        while ( (nr_pending != 0) && !RING_PLUGGED )
-            do_xlblk_request(pending_queues[--nr_pending]);
-    }
-}
-
-
-static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
-{
-    BLK_RING_IDX i; 
-    unsigned long flags; 
-    struct buffer_head *bh, *next_bh;
-    
-    if ( unlikely(state == STATE_CLOSED) )
-        return;
-    
-    spin_lock_irqsave(&io_request_lock, flags);     
-
-    for ( i = resp_cons; i != blk_ring->resp_prod; i++ )
-    {
-        blk_ring_resp_entry_t *bret = &blk_ring->ring[MASK_BLK_IDX(i)].resp;
-        switch ( bret->operation )
-        {
-        case XEN_BLOCK_READ:
-        case XEN_BLOCK_WRITE:
-            if ( unlikely(bret->status != 0) )
-                DPRINTK("Bad return from blkdev data request: %lx\n",
-                        bret->status);
-            for ( bh = (struct buffer_head *)bret->id; 
-                  bh != NULL; 
-                  bh = next_bh )
-            {
-                next_bh = bh->b_reqnext;
-                bh->b_reqnext = NULL;
-                bh->b_end_io(bh, !bret->status);
-            }
-            break;
-     
-        default:
-            BUG();
-        }
-    }
-    
-    resp_cons = i;
-
-    kick_pending_request_queues();
-
-    spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-
-static void reset_xlblk_interface(void)
-{
-    block_io_op_t op; 
-
-    nr_pending = 0;
-
-    op.cmd = BLOCK_IO_OP_RESET;
-    if ( HYPERVISOR_block_io_op(&op) != 0 )
-        printk(KERN_ALERT "Possible blkdev trouble: couldn't reset ring\n");
-
-    op.cmd = BLOCK_IO_OP_RING_ADDRESS;
-    (void)HYPERVISOR_block_io_op(&op);
-
-    set_fixmap(FIX_BLKRING_BASE, op.u.ring_mfn << PAGE_SHIFT);
-    blk_ring = (blk_ring_t *)fix_to_virt(FIX_BLKRING_BASE);
-    blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
-
-    wmb();
-    state = STATE_ACTIVE;
-}
-
-
-int __init xlblk_init(void)
-{
-    int error; 
-
-    reset_xlblk_interface();
-
-    error = request_irq(XLBLK_RESPONSE_IRQ, xlblk_response_int, 
-                        SA_SAMPLE_RANDOM, "blkdev", NULL);
-    if ( error )
-    {
-        printk(KERN_ALERT "Could not allocate receive interrupt\n");
-        goto fail;
-    }
-
-    error = request_irq(XLBLK_UPDATE_IRQ, xlblk_update_int,
-                        SA_INTERRUPT, "blkdev", NULL);
-
-    if ( error )
-    {
-        printk(KERN_ALERT "Could not allocate block update interrupt\n");
-        goto fail;
-    }
-
-    (void)xlvbd_init();
-
-    return 0;
-
- fail:
-    return error;
-}
-
-
-static void __exit xlblk_cleanup(void)
-{
-    xlvbd_cleanup();
-    free_irq(XLBLK_RESPONSE_IRQ, NULL);
-    free_irq(XLBLK_UPDATE_IRQ, NULL);
-}
-
-
-#ifdef MODULE
-module_init(xlblk_init);
-module_exit(xlblk_cleanup);
-#endif
-
-
-void blkdev_suspend(void)
-{
-    state = STATE_SUSPENDED;
-    wmb();
-
-    while ( resp_cons != blk_ring->req_prod )
-    {
-        barrier();
-        current->state = TASK_INTERRUPTIBLE;
-        schedule_timeout(1);
-    }
-
-    wmb();
-    state = STATE_CLOSED;
-    wmb();
-
-    clear_fixmap(FIX_BLKRING_BASE);
-}
-
-
-void blkdev_resume(void)
-{
-    reset_xlblk_interface();
-    spin_lock_irq(&io_request_lock);
-    kick_pending_request_queues();
-    spin_unlock_irq(&io_request_lock);
-}
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.h b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_block.h
deleted file mode 100644 (file)
index c735a6e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/******************************************************************************
- * xl_block.h
- * 
- * Shared definitions between all levels of XenoLinux Virtual block devices.
- */
-
-#ifndef __XL_BLOCK_H__
-#define __XL_BLOCK_H__
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-
-#include <linux/fs.h>
-#include <linux/hdreg.h>
-#include <linux/blkdev.h>
-#include <linux/major.h>
-
-#include <asm/hypervisor-ifs/hypervisor-if.h>
-#include <asm/hypervisor-ifs/vbd.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-
-#if 0
-#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#else
-#define DPRINTK(_f, _a...) ((void)0)
-#endif
-
-#if 0
-#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a )
-#else
-#define DPRINTK_IOCTL(_f, _a...) ((void)0)
-#endif
-
-/* Private gendisk->flags[] values. */
-#define GENHD_FL_XENO        2 /* Is unit a Xen block device?  */
-#define GENHD_FL_VIRT_PARTNS 4 /* Are unit partitions virtual? */
-
-/*
- * We have one of these per vbd, whether ide, scsi or 'other'.
- * They hang in an array off the gendisk structure. We may end up putting
- * all kinds of interesting stuff here :-)
- */
-typedef struct xl_disk {
-    int usage;
-} xl_disk_t;
-
-extern int xenolinux_control_msg(int operration, char *buffer, int size);
-extern int xenolinux_block_open(struct inode *inode, struct file *filep);
-extern int xenolinux_block_release(struct inode *inode, struct file *filep);
-extern int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
-                                 unsigned command, unsigned long argument);
-extern int xenolinux_block_check(kdev_t dev);
-extern int xenolinux_block_revalidate(kdev_t dev);
-extern void do_xlblk_request (request_queue_t *rq); 
-
-extern void xlvbd_update_vbds(void);
-
-static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
-{
-    struct gendisk *gd = get_gendisk(xldev);
-    
-    if ( gd == NULL ) 
-        return NULL;
-    
-    return (xl_disk_t *)gd->real_devices + 
-        (MINOR(xldev) >> gd->minor_shift);
-}
-
-
-/* Virtual block-device subsystem. */
-extern int  xlvbd_init(void);
-extern void xlvbd_cleanup(void); 
-
-#endif /* __XL_BLOCK_H__ */
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_vbd.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/block/xl_vbd.c
deleted file mode 100644 (file)
index cf39c5d..0000000
+++ /dev/null
@@ -1,561 +0,0 @@
-/******************************************************************************
- * xl_vbd.c
- * 
- * Xenolinux virtual block-device driver (xvd).
- * 
- * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
- * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
- */
-
-#include "xl_block.h"
-#include <linux/blk.h>
-
-/*
- * For convenience we distinguish between ide, scsi and 'other' (i.e.
- * potentially combinations of the two) in the naming scheme and in a few 
- * other places (like default readahead, etc).
- */
-#define XLIDE_MAJOR_NAME  "hd"
-#define XLSCSI_MAJOR_NAME "sd"
-#define XLVBD_MAJOR_NAME "xvd"
-
-#define XLIDE_DEVS_PER_MAJOR   2
-#define XLSCSI_DEVS_PER_MAJOR 16
-#define XLVBD_DEVS_PER_MAJOR  16
-
-#define XLIDE_PARTN_SHIFT  6    /* amount to shift minor to get 'real' minor */
-#define XLIDE_MAX_PART    (1 << XLIDE_PARTN_SHIFT)     /* minors per ide vbd */
-
-#define XLSCSI_PARTN_SHIFT 4    /* amount to shift minor to get 'real' minor */
-#define XLSCSI_MAX_PART   (1 << XLSCSI_PARTN_SHIFT)   /* minors per scsi vbd */
-
-#define XLVBD_PARTN_SHIFT  4    /* amount to shift minor to get 'real' minor */
-#define XLVBD_MAX_PART    (1 << XLVBD_PARTN_SHIFT) /* minors per 'other' vbd */
-
-/* The below are for the generic drivers/block/ll_rw_block.c code. */
-static int xlide_blksize_size[256];
-static int xlide_hardsect_size[256];
-static int xlide_max_sectors[256];
-static int xlscsi_blksize_size[256];
-static int xlscsi_hardsect_size[256];
-static int xlscsi_max_sectors[256];
-static int xlvbd_blksize_size[256];
-static int xlvbd_hardsect_size[256];
-static int xlvbd_max_sectors[256];
-
-/* Information from Xen about our VBDs. */
-#define MAX_VBDS 64
-static int nr_vbds;
-static xen_disk_t *vbd_info;
-
-static struct block_device_operations xlvbd_block_fops = 
-{
-    open:               xenolinux_block_open,
-    release:            xenolinux_block_release,
-    ioctl:              xenolinux_block_ioctl,
-    check_media_change: xenolinux_block_check,
-    revalidate:         xenolinux_block_revalidate,
-};
-
-static int xlvbd_get_vbd_info(xen_disk_t *disk_info)
-{
-    int error;
-    block_io_op_t op; 
-
-    /* Probe for disk information. */
-    memset(&op, 0, sizeof(op)); 
-    op.cmd = BLOCK_IO_OP_VBD_PROBE; 
-    op.u.probe_params.domain    = 0; 
-    op.u.probe_params.xdi.max   = MAX_VBDS;
-    op.u.probe_params.xdi.disks = disk_info;
-    op.u.probe_params.xdi.count = 0;
-
-    if ( (error = HYPERVISOR_block_io_op(&op)) != 0 )
-    {
-        printk(KERN_ALERT "Could not probe disks (%d)\n", error);
-        return -1;
-    }
-
-    return op.u.probe_params.xdi.count;
-}
-
-/*
- * xlvbd_init_device - initialise a VBD device
- * @disk:              a xen_disk_t describing the VBD
- *
- * Takes a xen_disk_t * that describes a VBD the domain has access to.
- * Performs appropriate initialisation and registration of the device.
- *
- * Care needs to be taken when making re-entrant calls to ensure that
- * corruption does not occur.  Also, devices that are in use should not have
- * their details updated.  This is the caller's responsibility.
- */
-static int xlvbd_init_device(xen_disk_t *xd)
-{
-    int device = xd->device;
-    int major  = MAJOR(device); 
-    int minor  = MINOR(device);
-    int is_ide = IDE_DISK_MAJOR(major);  /* is this an ide device? */
-    int is_scsi= SCSI_BLK_MAJOR(major);  /* is this a scsi device? */
-    char *major_name;
-    struct gendisk *gd;
-    struct block_device *bd;
-    xl_disk_t *disk;
-    int i, rc = 0, max_part, partno;
-    unsigned long capacity;
-
-    unsigned char buf[64];
-
-    if ( (bd = bdget(device)) == NULL )
-        return -1;
-
-    /*
-     * Update of partition info, and check of usage count, is protected
-     * by the per-block-device semaphore.
-     */
-    down(&bd->bd_sem);
-
-    if ( ((disk = xldev_to_xldisk(device)) != NULL) && (disk->usage != 0) )
-    {
-        printk(KERN_ALERT "VBD update failed - in use [dev=%x]\n", device);
-        rc = -1;
-        goto out;
-    }
-
-    if ( is_ide ) {
-
-       major_name = XLIDE_MAJOR_NAME; 
-       max_part   = XLIDE_MAX_PART;
-
-    } else if ( is_scsi ) {
-
-       major_name = XLSCSI_MAJOR_NAME;
-       max_part   = XLSCSI_MAX_PART;
-
-    } else if (XD_VIRTUAL(xd->info)) {
-
-       major_name = XLVBD_MAJOR_NAME;
-       max_part   = XLVBD_MAX_PART;
-
-    } else { 
-
-        /* SMH: hmm - probably a CCISS driver or sim; assume CCISS for now */
-       printk(KERN_ALERT "Assuming device %02x:%02x is CCISS/SCSI\n", 
-              major, minor);
-       is_scsi    = 1; 
-       major_name = "cciss"; 
-       max_part   = XLSCSI_MAX_PART;
-
-    }
-    
-    partno = minor & (max_part - 1); 
-    
-    if ( (gd = get_gendisk(device)) == NULL )
-    {
-        rc = register_blkdev(major, major_name, &xlvbd_block_fops);
-        if ( rc < 0 )
-        {
-            printk(KERN_ALERT "XL VBD: can't get major %d\n", major);
-            goto out;
-        }
-
-        if ( is_ide )
-        { 
-            blksize_size[major]  = xlide_blksize_size;
-            hardsect_size[major] = xlide_hardsect_size;
-            max_sectors[major]   = xlide_max_sectors;
-            read_ahead[major]    = 8; /* from drivers/ide/ide-probe.c */
-        } 
-        else if ( is_scsi )
-        { 
-            blksize_size[major]  = xlscsi_blksize_size;
-            hardsect_size[major] = xlscsi_hardsect_size;
-            max_sectors[major]   = xlscsi_max_sectors;
-            read_ahead[major]    = 0; /* XXX 8; -- guessing */
-        }
-        else
-        { 
-            blksize_size[major]  = xlvbd_blksize_size;
-            hardsect_size[major] = xlvbd_hardsect_size;
-            max_sectors[major]   = xlvbd_max_sectors;
-            read_ahead[major]    = 8;
-        }
-
-        blk_init_queue(BLK_DEFAULT_QUEUE(major), do_xlblk_request);
-
-        /*
-         * Turn off barking 'headactive' mode. We dequeue buffer heads as
-         * soon as we pass them down to Xen.
-         */
-        blk_queue_headactive(BLK_DEFAULT_QUEUE(major), 0);
-
-        /* Construct an appropriate gendisk structure. */
-        gd             = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
-        gd->major      = major;
-        gd->major_name = major_name; 
-    
-        gd->max_p      = max_part; 
-        if ( is_ide )
-        { 
-            gd->minor_shift  = XLIDE_PARTN_SHIFT; 
-            gd->nr_real      = XLIDE_DEVS_PER_MAJOR; 
-        } 
-        else if ( is_scsi )
-        { 
-            gd->minor_shift  = XLSCSI_PARTN_SHIFT; 
-            gd->nr_real      = XLSCSI_DEVS_PER_MAJOR; 
-        }
-        else
-        { 
-            gd->minor_shift  = XLVBD_PARTN_SHIFT; 
-            gd->nr_real      = XLVBD_DEVS_PER_MAJOR; 
-        }
-
-        /* 
-        ** The sizes[] and part[] arrays hold the sizes and other 
-        ** information about every partition with this 'major' (i.e. 
-        ** every disk sharing the 8 bit prefix * max partns per disk) 
-        */
-        gd->sizes = kmalloc(max_part*gd->nr_real*sizeof(int), GFP_KERNEL);
-        gd->part  = kmalloc(max_part*gd->nr_real*sizeof(struct hd_struct), 
-                            GFP_KERNEL);
-        memset(gd->sizes, 0, max_part * gd->nr_real * sizeof(int));
-        memset(gd->part,  0, max_part * gd->nr_real 
-               * sizeof(struct hd_struct));
-
-
-        gd->real_devices = kmalloc(gd->nr_real * sizeof(xl_disk_t), 
-                                   GFP_KERNEL);
-        memset(gd->real_devices, 0, gd->nr_real * sizeof(xl_disk_t));
-
-        gd->next   = NULL;            
-        gd->fops   = &xlvbd_block_fops;
-
-        gd->de_arr = kmalloc(gd->nr_real * sizeof(*gd->de_arr), 
-                             GFP_KERNEL);
-        gd->flags  = kmalloc(gd->nr_real * sizeof(*gd->flags), GFP_KERNEL);
-    
-        memset(gd->de_arr, 0, gd->nr_real * sizeof(*gd->de_arr));
-        memset(gd->flags, 0, gd->nr_real *  sizeof(*gd->flags));
-
-        add_gendisk(gd);
-
-        blk_size[major] = gd->sizes;
-    }
-
-    if ( XD_READONLY(xd->info) )
-        set_device_ro(device, 1); 
-
-    gd->flags[minor >> gd->minor_shift] |= GENHD_FL_XENO;
-
-    /* NB. Linux 2.4 only handles 32-bit sector offsets and capacities. */
-    capacity = (unsigned long)xd->capacity;
-
-    if ( partno != 0 )
-    {
-        /*
-         * If this was previously set up as a real disc we will have set 
-         * up partition-table information. Virtual partitions override 
-         * 'real' partitions, and the two cannot coexist on a device.
-         */
-        if ( !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) &&
-             (gd->sizes[minor & ~(max_part-1)] != 0) )
-        {
-            /*
-             * Any non-zero sub-partition entries must be cleaned out before
-             * installing 'virtual' partition entries. The two types cannot
-             * coexist, and virtual partitions are favoured.
-             */
-            kdev_t dev = device & ~(max_part-1);
-            for ( i = max_part - 1; i > 0; i-- )
-            {
-                invalidate_device(dev+i, 1);
-                gd->part[MINOR(dev+i)].start_sect = 0;
-                gd->part[MINOR(dev+i)].nr_sects   = 0;
-                gd->sizes[MINOR(dev+i)]           = 0;
-            }
-            printk(KERN_ALERT
-                   "Virtual partitions found for /dev/%s - ignoring any "
-                   "real partition information we may have found.\n",
-                   disk_name(gd, MINOR(device), buf));
-        }
-
-        /* Need to skankily setup 'partition' information */
-        gd->part[minor].start_sect = 0; 
-        gd->part[minor].nr_sects   = capacity; 
-        gd->sizes[minor]           = capacity; 
-
-        gd->flags[minor >> gd->minor_shift] |= GENHD_FL_VIRT_PARTNS;
-    }
-    else
-    {
-        gd->part[minor].nr_sects = capacity;
-        gd->sizes[minor] = capacity>>(BLOCK_SIZE_BITS-9);
-        
-        /* Some final fix-ups depending on the device type */
-        switch ( XD_TYPE(xd->info) )
-        { 
-        case XD_TYPE_CDROM:
-        case XD_TYPE_FLOPPY: 
-        case XD_TYPE_TAPE:
-            gd->flags[minor >> gd->minor_shift] |= GENHD_FL_REMOVABLE; 
-            printk(KERN_ALERT 
-                   "Skipping partition check on %s /dev/%s\n", 
-                   XD_TYPE(xd->info)==XD_TYPE_CDROM ? "cdrom" : 
-                   (XD_TYPE(xd->info)==XD_TYPE_TAPE ? "tape" : 
-                    "floppy"), disk_name(gd, MINOR(device), buf)); 
-            break; 
-
-        case XD_TYPE_DISK:
-            /* Only check partitions on real discs (not virtual!). */
-            if ( gd->flags[minor>>gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
-            {
-                printk(KERN_ALERT
-                       "Skipping partition check on virtual /dev/%s\n",
-                       disk_name(gd, MINOR(device), buf));
-                break;
-            }
-            register_disk(gd, device, gd->max_p, &xlvbd_block_fops, capacity);
-            break; 
-
-        default:
-            printk(KERN_ALERT "XenoLinux: unknown device type %d\n", 
-                   XD_TYPE(xd->info)); 
-            break; 
-        }
-    }
-
- out:
-    up(&bd->bd_sem);
-    bdput(bd);    
-    return rc;
-}
-
-
-/*
- * xlvbd_remove_device - remove a device node if possible
- * @device:       numeric device ID
- *
- * Updates the gendisk structure and invalidates devices.
- *
- * This is OK for now but in future, should perhaps consider where this should
- * deallocate gendisks / unregister devices.
- */
-static int xlvbd_remove_device(int device)
-{
-    int i, rc = 0, minor = MINOR(device);
-    struct gendisk *gd;
-    struct block_device *bd;
-    xl_disk_t *disk = NULL;
-
-    if ( (bd = bdget(device)) == NULL )
-        return -1;
-
-    /*
-     * Update of partition info, and check of usage count, is protected
-     * by the per-block-device semaphore.
-     */
-    down(&bd->bd_sem);
-
-    if ( ((gd = get_gendisk(device)) == NULL) ||
-         ((disk = xldev_to_xldisk(device)) == NULL) )
-        BUG();
-
-    if ( disk->usage != 0 )
-    {
-        printk(KERN_ALERT "VBD removal failed - in use [dev=%x]\n", device);
-        rc = -1;
-        goto out;
-    }
-    if ( (minor & (gd->max_p-1)) != 0 )
-    {
-        /* 1: The VBD is mapped to a partition rather than a whole unit. */
-        invalidate_device(device, 1);
-       gd->part[minor].start_sect = 0;
-        gd->part[minor].nr_sects   = 0;
-        gd->sizes[minor]           = 0;
-
-        /* Clear the consists-of-virtual-partitions flag if possible. */
-        gd->flags[minor >> gd->minor_shift] &= ~GENHD_FL_VIRT_PARTNS;
-        for ( i = 1; i < gd->max_p; i++ )
-            if ( gd->sizes[(minor & ~(gd->max_p-1)) + i] != 0 )
-                gd->flags[minor >> gd->minor_shift] |= GENHD_FL_VIRT_PARTNS;
-
-        /*
-         * If all virtual partitions are now gone, and a 'whole unit' VBD is
-         * present, then we can try to grok the unit's real partition table.
-         */
-        if ( !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) &&
-             (gd->sizes[minor & ~(gd->max_p-1)] != 0) &&
-             !(gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE) )
-        {
-            register_disk(gd,
-                          device&~(gd->max_p-1), 
-                          gd->max_p, 
-                          &xlvbd_block_fops,
-                          gd->part[minor&~(gd->max_p-1)].nr_sects);
-        }
-    }
-    else
-    {
-        /*
-         * 2: The VBD is mapped to an entire 'unit'. Clear all partitions.
-         * NB. The partition entries are only cleared if there are no VBDs
-         * mapped to individual partitions on this unit.
-         */
-        i = gd->max_p - 1; /* Default: clear subpartitions as well. */
-        if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS )
-            i = 0; /* 'Virtual' mode: only clear the 'whole unit' entry. */
-        while ( i >= 0 )
-        {
-            invalidate_device(device+i, 1);
-            gd->part[minor+i].start_sect = 0;
-            gd->part[minor+i].nr_sects   = 0;
-            gd->sizes[minor+i]           = 0;
-            i--;
-        }
-    }
-
- out:
-    up(&bd->bd_sem);
-    bdput(bd);
-    return rc;
-}
-
-/*
- * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
- * state. The VBDs need to be updated in this way when the domain is
- * initialised and also each time we receive an XLBLK_UPDATE event.
- */
-void xlvbd_update_vbds(void)
-{
-    int i, j, k, old_nr, new_nr;
-    xen_disk_t *old_info, *new_info, *merged_info;
-
-    old_info = vbd_info;
-    old_nr   = nr_vbds;
-
-    new_info = kmalloc(MAX_VBDS * sizeof(xen_disk_t), GFP_KERNEL);
-    if ( unlikely(new_nr = xlvbd_get_vbd_info(new_info)) < 0 )
-    {
-        kfree(new_info);
-        return;
-    }
-
-    /*
-     * Final list maximum size is old list + new list. This occurs only when
-     * old list and new list do not overlap at all, and we cannot yet destroy
-     * VBDs in the old list because the usage counts are busy.
-     */
-    merged_info = kmalloc((old_nr + new_nr) * sizeof(xen_disk_t), GFP_KERNEL);
-
-    /* @i tracks old list; @j tracks new list; @k tracks merged list. */
-    i = j = k = 0;
-
-    while ( (i < old_nr) && (j < new_nr) )
-    {
-        if ( old_info[i].device < new_info[j].device )
-        {
-            if ( xlvbd_remove_device(old_info[i].device) != 0 )
-                memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
-            i++;
-        }
-        else if ( old_info[i].device > new_info[j].device )
-        {
-            if ( xlvbd_init_device(&new_info[j]) == 0 )
-                memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
-            j++;
-        }
-        else
-        {
-            if ( ((old_info[i].capacity == new_info[j].capacity) &&
-                  (old_info[i].info == new_info[j].info)) ||
-                 (xlvbd_remove_device(old_info[i].device) != 0) )
-                memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
-            else if ( xlvbd_init_device(&new_info[j]) == 0 )
-                memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
-            i++; j++;
-        }
-    }
-
-    for ( ; i < old_nr; i++ )
-    {
-        if ( xlvbd_remove_device(old_info[i].device) != 0 )
-            memcpy(&merged_info[k++], &old_info[i], sizeof(xen_disk_t));
-    }
-
-    for ( ; j < new_nr; j++ )
-    {
-        if ( xlvbd_init_device(&new_info[j]) == 0 )
-            memcpy(&merged_info[k++], &new_info[j], sizeof(xen_disk_t));
-    }
-
-    vbd_info = merged_info;
-    nr_vbds  = k;
-
-    kfree(old_info);
-    kfree(new_info);
-}
-
-
-/*
- * Set up all the linux device goop for the virtual block devices (vbd's) that 
- * xen tells us about. Note that although from xen's pov VBDs are addressed 
- * simply an opaque 16-bit device number, the domain creation tools 
- * conventionally allocate these numbers to correspond to those used by 'real' 
- * linux -- this is just for convenience as it means e.g. that the same 
- * /etc/fstab can be used when booting with or without xen.
- */
-int __init xlvbd_init(void)
-{
-    int i;
-    
-    /*
-     * If compiled as a module, we don't support unloading yet. We therefore 
-     * permanently increment the reference count to disallow it.
-     */
-    SET_MODULE_OWNER(&xlvbd_block_fops);
-    MOD_INC_USE_COUNT;
-
-    /* Initialize the global arrays. */
-    for ( i = 0; i < 256; i++ ) 
-    {
-        /* from the generic ide code (drivers/ide/ide-probe.c, etc) */
-        xlide_blksize_size[i]  = 1024;
-        xlide_hardsect_size[i] = 512;
-        xlide_max_sectors[i]   = 128;  /* 'hwif->rqsize' if we knew it */
-
-        /* from the generic scsi disk code (drivers/scsi/sd.c) */
-        xlscsi_blksize_size[i]  = 1024; /* XXX 512; */
-        xlscsi_hardsect_size[i] = 512;
-        xlscsi_max_sectors[i]   = 128*8; /* XXX 128; */
-
-        /* we don't really know what to set these too since it depends */
-        xlvbd_blksize_size[i]  = 512;
-        xlvbd_hardsect_size[i] = 512;
-        xlvbd_max_sectors[i]   = 128;
-    }
-
-    vbd_info = kmalloc(MAX_VBDS * sizeof(xen_disk_t), GFP_KERNEL);
-    nr_vbds  = xlvbd_get_vbd_info(vbd_info);
-
-    if ( nr_vbds < 0 )
-    {
-        kfree(vbd_info);
-        vbd_info = NULL;
-        nr_vbds  = 0;
-    }
-    else
-    {
-        for ( i = 0; i < nr_vbds; i++ )
-            xlvbd_init_device(&vbd_info[i]);
-    }
-
-    return 0;
-}
-
-
-#ifdef MODULE
-module_init(xlvbd_init);
-#endif
index 546180a3c271cba4b1a69c96b65b6ab20f503321..aaa546a8f31b022c2fc6e91f5c2b6a6986b75a6f 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := con.o
+O_TARGET := drv.o
 obj-$(CONFIG_XEN_CONSOLE) := console.o
 include $(TOPDIR)/Rules.make
index 9030801f1423a12df2421e7d1325acaf1ffb5b71..3e2e17bd239c61b4b6da270a02ba3041aa6b6561 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := dom0.o
-obj-y := dom0_core.o vfr.o
+O_TARGET := drv.o
+obj-y := core.o vfr.o
 include $(TOPDIR)/Rules.make
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/core.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/core.c
new file mode 100644 (file)
index 0000000..c7f1fd4
--- /dev/null
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * core.c
+ * 
+ * Interface to privileged domain-0 commands.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/swapctl.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+#include <asm/proc_cmd.h>
+#include <asm/hypervisor-ifs/dom0_ops.h>
+#include <asm/xeno_proc.h>
+
+static struct proc_dir_entry *privcmd_intf;
+
+static int privcmd_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long data)
+{
+    int ret = 0;
+
+    switch ( cmd )
+    {
+    case IOCTL_PRIVCMD_HYPERCALL:
+    {
+        privcmd_hypercall_t hypercall;
+  
+        if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
+            return -EFAULT;
+
+        __asm__ __volatile__ (
+            "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
+            "movl  4(%%eax),%%ebx ;"
+            "movl  8(%%eax),%%ecx ;"
+            "movl 12(%%eax),%%edx ;"
+            "movl 16(%%eax),%%esi ;"
+            "movl 20(%%eax),%%edi ;"
+            "movl   (%%eax),%%eax ;"
+            TRAP_INSTR "; "
+            "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
+            : "=a" (ret) : "0" (&hypercall) : "memory" );
+
+    }
+    break;
+
+    default:
+        ret = -EINVAL;
+       break;
+       }
+    return ret;
+}
+
+
+static struct file_operations privcmd_file_ops = {
+  ioctl : privcmd_ioctl
+};
+
+
+static int __init init_module(void)
+{
+    if ( !(start_info.flags & SIF_PRIVILEGED) )
+        return 0;
+
+    privcmd_intf = create_xeno_proc_entry("privcmd", 0400);
+    if ( privcmd_intf != NULL )
+    {
+        privcmd_intf->owner      = THIS_MODULE;
+        privcmd_intf->nlink      = 1;
+       privcmd_intf->proc_fops  = &privcmd_file_ops;
+    }
+
+    return 0;
+}
+
+
+static void __exit cleanup_module(void)
+{
+    if ( privcmd_intf == NULL ) return;
+    remove_xeno_proc_entry("privcmd");
+    privcmd_intf = NULL;
+}
+
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/dom0/dom0_core.c
deleted file mode 100644 (file)
index 08144d9..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/******************************************************************************
- * dom0_core.c
- * 
- * Interface to privileged domain-0 commands.
- * 
- * Copyright (c) 2002-2003, K A Fraser, B Dragovic
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/swapctl.h>
-#include <linux/iobuf.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/seq_file.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/tlb.h>
-#include <asm/proc_cmd.h>
-#include <asm/hypervisor-ifs/dom0_ops.h>
-#include <asm/xeno_proc.h>
-
-#include "../block/xl_block.h"
-
-static struct proc_dir_entry *privcmd_intf;
-
-
-static int privcmd_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long data)
-{
-    int ret = 0;
-
-    switch ( cmd )
-    {
-    case IOCTL_PRIVCMD_HYPERCALL:
-    {
-        privcmd_hypercall_t hypercall;
-  
-        if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
-            return -EFAULT;
-
-        __asm__ __volatile__ (
-            "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
-            "movl  4(%%eax),%%ebx ;"
-            "movl  8(%%eax),%%ecx ;"
-            "movl 12(%%eax),%%edx ;"
-            "movl 16(%%eax),%%esi ;"
-            "movl 20(%%eax),%%edi ;"
-            "movl   (%%eax),%%eax ;"
-            TRAP_INSTR "; "
-            "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
-            : "=a" (ret) : "0" (&hypercall) : "memory" );
-
-    }
-    break;
-
-    default:
-        ret = -EINVAL;
-       break;
-       }
-    return ret;
-}
-
-
-static struct file_operations privcmd_file_ops = {
-  ioctl : privcmd_ioctl
-};
-
-
-static int __init init_module(void)
-{
-    if ( !(start_info.flags & SIF_PRIVILEGED) )
-        return 0;
-
-    /* xeno control interface */
-    privcmd_intf = create_xeno_proc_entry("privcmd", 0400);
-    if ( privcmd_intf != NULL )
-    {
-        privcmd_intf->owner      = THIS_MODULE;
-        privcmd_intf->nlink      = 1;
-       privcmd_intf->proc_fops  = &privcmd_file_ops;
-    }
-
-    return 0;
-}
-
-
-static void __exit cleanup_module(void)
-{
-    if ( privcmd_intf == NULL ) return;
-    remove_xeno_proc_entry("privcmd");
-    privcmd_intf = NULL;
-}
-
-
-module_init(init_module);
-module_exit(cleanup_module);
index 8384c8658b62842893233d7fbf883e534ff46343..61c983f625c9a86258038265210b7bc211c6d6d6 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := evtchn.o
-obj-y := xl_evtchn.o
+O_TARGET := drv.o
+obj-y := evtchn.o
 include $(TOPDIR)/Rules.make
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/evtchn.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/evtchn.c
new file mode 100644 (file)
index 0000000..a7978ee
--- /dev/null
@@ -0,0 +1,481 @@
+/******************************************************************************
+ * evtchn.c
+ * 
+ * Xenolinux driver for receiving and demuxing event-channel signals.
+ * 
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/stat.h>
+#include <linux/poll.h>
+#include <linux/irq.h>
+#include <asm/evtchn.h>
+
+/* NB. This must be shared amongst drivers if more things go in /dev/xen */
+static devfs_handle_t xen_dev_dir;
+
+/* Only one process may open /dev/xen/evtchn at any time. */
+static unsigned long evtchn_dev_inuse;
+
+/* Notification ring, accessed via /dev/xen/evtchn. */
+#define RING_SIZE     2048  /* 2048 16-bit entries */
+#define RING_MASK(_i) ((_i)&(RING_SIZE-1))
+static u16 *ring;
+static unsigned int ring_cons, ring_prod, ring_overflow;
+
+/* Processes wait on this queue via /dev/xen/evtchn when ring is empty. */
+static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
+static struct fasync_struct *evtchn_async_queue;
+
+static evtchn_receiver_t rx_fns[1024];
+
+static u32 pend_outstanding[32];
+static u32 disc_outstanding[32];
+
+static spinlock_t lock;
+
+int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn)
+{
+    unsigned long flags;
+    int rc;
+
+    spin_lock_irqsave(&lock, flags);
+
+    if ( rx_fns[port] != NULL )
+    {
+        printk(KERN_ALERT "Event channel port %d already in use.\n", port);
+        rc = -EINVAL;
+    }
+    else
+    {
+        rx_fns[port] = rx_fn;
+        rc = 0;
+    }
+
+    spin_unlock_irqrestore(&lock, flags);
+
+    return rc;
+}
+
+int evtchn_free_port(unsigned int port)
+{
+    unsigned long flags;
+    int rc;
+
+    spin_lock_irqsave(&lock, flags);
+
+    if ( rx_fns[port] == NULL )
+    {
+        printk(KERN_ALERT "Event channel port %d not in use.\n", port);
+        rc = -EINVAL;
+    }
+    else
+    {
+        rx_fns[port] = NULL;
+        rc = 0;
+    }
+
+    spin_unlock_irqrestore(&lock, flags);
+
+    return rc;
+}
+
+/*
+ * NB. Clearing port can race a notification from remote end. Caller must
+ * therefore recheck notification status on return to avoid missing events.
+ */
+void evtchn_clear_port(unsigned int port)
+{
+    unsigned int p = port & PORTIDX_MASK;
+    unsigned long flags;
+
+    spin_lock_irqsave(&lock, flags);
+
+    if ( unlikely(port & PORT_DISCONNECT) )
+    {
+        clear_bit(p, &disc_outstanding[0]);
+        clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
+    }
+    else
+    {
+        clear_bit(p, &pend_outstanding[0]);
+        clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
+    }
+
+    spin_unlock_irqrestore(&lock, flags);
+}
+
+static inline void process_bitmask(u32 *sel, 
+                                   u32 *mask,
+                                   u32 *outstanding,
+                                   unsigned int port_subtype)
+{
+    unsigned long l1, l2;
+    unsigned int  l1_idx, l2_idx, port;
+
+    l1 = xchg(sel, 0);
+    while ( (l1_idx = ffs(l1)) != 0 )
+    {
+        l1_idx--;
+        l1 &= ~(1 << l1_idx);
+
+        l2 = mask[l1_idx] & ~outstanding[l1_idx];
+        outstanding[l1_idx] |= l2;
+        while ( (l2_idx = ffs(l2)) != 0 )
+        {
+            l2_idx--;
+            l2 &= ~(1 << l2_idx);
+
+            port = (l1_idx * 32) + l2_idx;
+            if ( rx_fns[port] != NULL )
+            {
+                (*rx_fns[port])(port | port_subtype);
+            }
+            else if ( ring != NULL )
+            {
+                if ( (ring_prod - ring_cons) < RING_SIZE )
+                {
+                    ring[RING_MASK(ring_prod)] = (u16)(port | port_subtype);
+                    if ( ring_cons == ring_prod++ )
+                    {
+                        wake_up_interruptible(&evtchn_wait);
+                        kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
+                    }
+                }
+                else
+                {
+                    ring_overflow = 1;
+                }
+            }
+        }
+    }
+}
+
+static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    shared_info_t *si = HYPERVISOR_shared_info;
+    unsigned long flags;
+
+    spin_lock_irqsave(&lock, flags);
+
+    process_bitmask(&si->event_channel_pend_sel, 
+                    &si->event_channel_pend[0],
+                    &pend_outstanding[0],
+                    PORT_NORMAL);
+        
+    process_bitmask(&si->event_channel_disc_sel,
+                    &si->event_channel_disc[0],
+                    &disc_outstanding[0],
+                    PORT_DISCONNECT);
+        
+    spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __evtchn_reset_buffer_ring(void)
+{
+    u32          m;
+    unsigned int i, j;
+
+    /* Initialise the ring with currently outstanding notifications. */
+    ring_cons = ring_prod = ring_overflow = 0;
+
+    for ( i = 0; i < 32; i++ )
+    {
+        m = pend_outstanding[i];
+        while ( (j = ffs(m)) != 0 )
+        {
+            m &= ~(1 << --j);
+            if ( rx_fns[(i * 32) + j] == NULL )
+                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
+        }
+
+        m = disc_outstanding[i];
+        while ( (j = ffs(m)) != 0 )
+        {
+            m &= ~(1 << --j);
+            if ( rx_fns[(i * 32) + j] == NULL )
+                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
+        }
+    }
+}
+
+static ssize_t evtchn_read(struct file *file, char *buf,
+                           size_t count, loff_t *ppos)
+{
+    int rc;
+    unsigned int c, p, bytes1 = 0, bytes2 = 0;
+    DECLARE_WAITQUEUE(wait, current);
+
+    add_wait_queue(&evtchn_wait, &wait);
+
+    count &= ~1; /* even number of bytes */
+
+    if ( count == 0 )
+    {
+        rc = 0;
+        goto out;
+    }
+
+    if ( count > PAGE_SIZE )
+        count = PAGE_SIZE;
+
+    for ( ; ; )
+    {
+        set_current_state(TASK_INTERRUPTIBLE);
+
+        if ( (c = ring_cons) != (p = ring_prod) )
+            break;
+
+        if ( ring_overflow )
+        {
+            rc = -EFBIG;
+            goto out;
+        }
+
+        if ( file->f_flags & O_NONBLOCK )
+        {
+            rc = -EAGAIN;
+            goto out;
+        }
+
+        if ( signal_pending(current) )
+        {
+            rc = -ERESTARTSYS;
+            goto out;
+        }
+
+        schedule();
+    }
+
+    /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
+    if ( ((c ^ p) & RING_SIZE) != 0 )
+    {
+        bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
+        bytes2 = RING_MASK(p) * sizeof(u16);
+    }
+    else
+    {
+        bytes1 = (p - c) * sizeof(u16);
+        bytes2 = 0;
+    }
+
+    /* Truncate chunks according to caller's maximum byte count. */
+    if ( bytes1 > count )
+    {
+        bytes1 = count;
+        bytes2 = 0;
+    }
+    else if ( (bytes1 + bytes2) > count )
+    {
+        bytes2 = count - bytes1;
+    }
+
+    if ( copy_to_user(buf, &ring[RING_MASK(c)], bytes1) ||
+         ((bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2)) )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    ring_cons += (bytes1 + bytes2) / sizeof(u16);
+
+    rc = bytes1 + bytes2;
+
+ out:
+    __set_current_state(TASK_RUNNING);
+    remove_wait_queue(&evtchn_wait, &wait);
+    return rc;
+}
+
+static ssize_t evtchn_write(struct file *file, const char *buf,
+                            size_t count, loff_t *ppos)
+{
+    int  rc, i;
+    u16 *kbuf = (u16 *)get_free_page(GFP_KERNEL);
+
+    if ( kbuf == NULL )
+        return -ENOMEM;
+
+    count &= ~1; /* even number of bytes */
+
+    if ( count == 0 )
+    {
+        rc = 0;
+        goto out;
+    }
+
+    if ( count > PAGE_SIZE )
+        count = PAGE_SIZE;
+
+    if ( copy_from_user(kbuf, buf, count) != 0 )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
+    for ( i = 0; i < (count/2); i++ )
+        evtchn_clear_port(kbuf[i]);
+
+    rc = count;
+
+ out:
+    free_page((unsigned long)kbuf);
+    return rc;
+}
+
+static int evtchn_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+    if ( cmd != EVTCHN_RESET )
+        return -EINVAL;
+
+    spin_lock_irq(&lock);
+    __evtchn_reset_buffer_ring();
+    spin_unlock_irq(&lock);   
+
+    return 0;
+}
+
+static unsigned int evtchn_poll(struct file *file, poll_table *wait)
+{
+    unsigned int mask = POLLOUT | POLLWRNORM;
+    poll_wait(file, &evtchn_wait, wait);
+    if ( ring_cons != ring_prod )
+        mask |= POLLIN | POLLRDNORM;
+    if ( ring_overflow )
+        mask = POLLERR;
+    return mask;
+}
+
+static int evtchn_fasync(int fd, struct file *filp, int on)
+{
+    return fasync_helper(fd, filp, on, &evtchn_async_queue);
+}
+
+static int evtchn_open(struct inode *inode, struct file *filp)
+{
+    u16 *_ring;
+
+    if ( test_and_set_bit(0, &evtchn_dev_inuse) )
+        return -EBUSY;
+
+    /* Allocate outside locked region so that we can use GFP_KERNEL. */
+    if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
+        return -ENOMEM;
+
+    spin_lock_irq(&lock);
+    ring = _ring;
+    __evtchn_reset_buffer_ring();
+    spin_unlock_irq(&lock);
+
+    MOD_INC_USE_COUNT;
+
+    return 0;
+}
+
+static int evtchn_release(struct inode *inode, struct file *filp)
+{
+    spin_lock_irq(&lock);
+    if ( ring != NULL )
+    {
+        free_page((unsigned long)ring);
+        ring = NULL;
+    }
+    spin_unlock_irq(&lock);
+
+    evtchn_dev_inuse = 0;
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+}
+
+static struct file_operations evtchn_fops = {
+    owner:    THIS_MODULE,
+    read:     evtchn_read,
+    write:    evtchn_write,
+    ioctl:    evtchn_ioctl,
+    poll:     evtchn_poll,
+    fasync:   evtchn_fasync,
+    open:     evtchn_open,
+    release:  evtchn_release
+};
+
+static struct miscdevice evtchn_miscdev = {
+    minor:    EVTCHN_MINOR,
+    name:     "evtchn",
+    fops:     &evtchn_fops
+};
+
+static int __init init_module(void)
+{
+    devfs_handle_t symlink_handle;
+    int            err, pos;
+    char           link_dest[64];
+
+    /* (DEVFS) create '/dev/misc/evtchn'. */
+    err = misc_register(&evtchn_miscdev);
+    if ( err != 0 )
+    {
+        printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
+        return err;
+    }
+
+    /* (DEVFS) create directory '/dev/xen'. */
+    xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
+
+    /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
+    pos = devfs_generate_path(evtchn_miscdev.devfs_handle, 
+                              &link_dest[3], 
+                              sizeof(link_dest) - 3);
+    if ( pos >= 0 )
+        strncpy(&link_dest[pos], "../", 3);
+
+    /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
+    (void)devfs_mk_symlink(xen_dev_dir, 
+                           "evtchn", 
+                           DEVFS_FL_DEFAULT, 
+                           &link_dest[pos],
+                           &symlink_handle, 
+                           NULL);
+
+    /* (DEVFS) automatically destroy the symlink with its destination. */
+    devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
+
+    err = request_irq(HYPEREVENT_IRQ(_EVENT_EVTCHN),
+                      evtchn_interrupt, 0, "evtchn", NULL);
+    if ( err != 0 )
+    {
+        printk(KERN_ALERT "Could not allocate evtchn receive interrupt\n");
+        return err;
+    }
+
+    /* Kickstart servicing of notifications. */
+    evtchn_interrupt(0, NULL, NULL);
+
+    printk("Event-channel driver installed.\n");
+
+    return 0;
+}
+
+static void cleanup_module(void)
+{
+    free_irq(HYPEREVENT_IRQ(_EVENT_EVTCHN), NULL);
+    misc_deregister(&evtchn_miscdev);
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c
deleted file mode 100644 (file)
index f642d08..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/******************************************************************************
- * xl_evtchn.c
- * 
- * Xenolinux driver for receiving and demuxing event-channel signals.
- * 
- * Copyright (c) 2004, K A Fraser
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/major.h>
-#include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/stat.h>
-#include <linux/poll.h>
-#include <linux/irq.h>
-#include <asm/evtchn.h>
-
-/* NB. This must be shared amongst drivers if more things go in /dev/xen */
-static devfs_handle_t xen_dev_dir;
-
-/* Only one process may open /dev/xen/evtchn at any time. */
-static unsigned long evtchn_dev_inuse;
-
-/* Notification ring, accessed via /dev/xen/evtchn. */
-#define RING_SIZE     2048  /* 2048 16-bit entries */
-#define RING_MASK(_i) ((_i)&(RING_SIZE-1))
-static u16 *ring;
-static unsigned int ring_cons, ring_prod, ring_overflow;
-
-/* Processes wait on this queue via /dev/xen/evtchn when ring is empty. */
-static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait);
-static struct fasync_struct *evtchn_async_queue;
-
-static evtchn_receiver_t rx_fns[1024];
-
-static u32 pend_outstanding[32];
-static u32 disc_outstanding[32];
-
-static spinlock_t lock;
-
-int evtchn_request_port(unsigned int port, evtchn_receiver_t rx_fn)
-{
-    unsigned long flags;
-    int rc;
-
-    spin_lock_irqsave(&lock, flags);
-
-    if ( rx_fns[port] != NULL )
-    {
-        printk(KERN_ALERT "Event channel port %d already in use.\n", port);
-        rc = -EINVAL;
-    }
-    else
-    {
-        rx_fns[port] = rx_fn;
-        rc = 0;
-    }
-
-    spin_unlock_irqrestore(&lock, flags);
-
-    return rc;
-}
-
-int evtchn_free_port(unsigned int port)
-{
-    unsigned long flags;
-    int rc;
-
-    spin_lock_irqsave(&lock, flags);
-
-    if ( rx_fns[port] == NULL )
-    {
-        printk(KERN_ALERT "Event channel port %d not in use.\n", port);
-        rc = -EINVAL;
-    }
-    else
-    {
-        rx_fns[port] = NULL;
-        rc = 0;
-    }
-
-    spin_unlock_irqrestore(&lock, flags);
-
-    return rc;
-}
-
-/*
- * NB. Clearing port can race a notification from remote end. Caller must
- * therefore recheck notification status on return to avoid missing events.
- */
-void evtchn_clear_port(unsigned int port)
-{
-    unsigned int p = port & PORTIDX_MASK;
-    unsigned long flags;
-
-    spin_lock_irqsave(&lock, flags);
-
-    if ( unlikely(port & PORT_DISCONNECT) )
-    {
-        clear_bit(p, &disc_outstanding[0]);
-        clear_bit(p, &HYPERVISOR_shared_info->event_channel_disc[0]);
-    }
-    else
-    {
-        clear_bit(p, &pend_outstanding[0]);
-        clear_bit(p, &HYPERVISOR_shared_info->event_channel_pend[0]);
-    }
-
-    spin_unlock_irqrestore(&lock, flags);
-}
-
-static inline void process_bitmask(u32 *sel, 
-                                   u32 *mask,
-                                   u32 *outstanding,
-                                   unsigned int port_subtype)
-{
-    unsigned long l1, l2;
-    unsigned int  l1_idx, l2_idx, port;
-
-    l1 = xchg(sel, 0);
-    while ( (l1_idx = ffs(l1)) != 0 )
-    {
-        l1_idx--;
-        l1 &= ~(1 << l1_idx);
-
-        l2 = mask[l1_idx] & ~outstanding[l1_idx];
-        outstanding[l1_idx] |= l2;
-        while ( (l2_idx = ffs(l2)) != 0 )
-        {
-            l2_idx--;
-            l2 &= ~(1 << l2_idx);
-
-            port = (l1_idx * 32) + l2_idx;
-            if ( rx_fns[port] != NULL )
-            {
-                (*rx_fns[port])(port | port_subtype);
-            }
-            else if ( ring != NULL )
-            {
-                if ( (ring_prod - ring_cons) < RING_SIZE )
-                {
-                    ring[RING_MASK(ring_prod)] = (u16)(port | port_subtype);
-                    if ( ring_cons == ring_prod++ )
-                    {
-                        wake_up_interruptible(&evtchn_wait);
-                        kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN);
-                    }
-                }
-                else
-                {
-                    ring_overflow = 1;
-                }
-            }
-        }
-    }
-}
-
-static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-    shared_info_t *si = HYPERVISOR_shared_info;
-    unsigned long flags;
-
-    spin_lock_irqsave(&lock, flags);
-
-    process_bitmask(&si->event_channel_pend_sel, 
-                    &si->event_channel_pend[0],
-                    &pend_outstanding[0],
-                    PORT_NORMAL);
-        
-    process_bitmask(&si->event_channel_disc_sel,
-                    &si->event_channel_disc[0],
-                    &disc_outstanding[0],
-                    PORT_DISCONNECT);
-        
-    spin_unlock_irqrestore(&lock, flags);
-}
-
-static void __evtchn_reset_buffer_ring(void)
-{
-    u32          m;
-    unsigned int i, j;
-
-    /* Initialise the ring with currently outstanding notifications. */
-    ring_cons = ring_prod = ring_overflow = 0;
-
-    for ( i = 0; i < 32; i++ )
-    {
-        m = pend_outstanding[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            if ( rx_fns[(i * 32) + j] == NULL )
-                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL);
-        }
-
-        m = disc_outstanding[i];
-        while ( (j = ffs(m)) != 0 )
-        {
-            m &= ~(1 << --j);
-            if ( rx_fns[(i * 32) + j] == NULL )
-                ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT);
-        }
-    }
-}
-
-static ssize_t evtchn_read(struct file *file, char *buf,
-                           size_t count, loff_t *ppos)
-{
-    int rc;
-    unsigned int c, p, bytes1 = 0, bytes2 = 0;
-    DECLARE_WAITQUEUE(wait, current);
-
-    add_wait_queue(&evtchn_wait, &wait);
-
-    count &= ~1; /* even number of bytes */
-
-    if ( count == 0 )
-    {
-        rc = 0;
-        goto out;
-    }
-
-    if ( count > PAGE_SIZE )
-        count = PAGE_SIZE;
-
-    for ( ; ; )
-    {
-        set_current_state(TASK_INTERRUPTIBLE);
-
-        if ( (c = ring_cons) != (p = ring_prod) )
-            break;
-
-        if ( ring_overflow )
-        {
-            rc = -EFBIG;
-            goto out;
-        }
-
-        if ( file->f_flags & O_NONBLOCK )
-        {
-            rc = -EAGAIN;
-            goto out;
-        }
-
-        if ( signal_pending(current) )
-        {
-            rc = -ERESTARTSYS;
-            goto out;
-        }
-
-        schedule();
-    }
-
-    /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
-    if ( ((c ^ p) & RING_SIZE) != 0 )
-    {
-        bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
-        bytes2 = RING_MASK(p) * sizeof(u16);
-    }
-    else
-    {
-        bytes1 = (p - c) * sizeof(u16);
-        bytes2 = 0;
-    }
-
-    /* Truncate chunks according to caller's maximum byte count. */
-    if ( bytes1 > count )
-    {
-        bytes1 = count;
-        bytes2 = 0;
-    }
-    else if ( (bytes1 + bytes2) > count )
-    {
-        bytes2 = count - bytes1;
-    }
-
-    if ( copy_to_user(buf, &ring[RING_MASK(c)], bytes1) ||
-         ((bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2)) )
-    {
-        rc = -EFAULT;
-        goto out;
-    }
-
-    ring_cons += (bytes1 + bytes2) / sizeof(u16);
-
-    rc = bytes1 + bytes2;
-
- out:
-    __set_current_state(TASK_RUNNING);
-    remove_wait_queue(&evtchn_wait, &wait);
-    return rc;
-}
-
-static ssize_t evtchn_write(struct file *file, const char *buf,
-                            size_t count, loff_t *ppos)
-{
-    int  rc, i;
-    u16 *kbuf = (u16 *)get_free_page(GFP_KERNEL);
-
-    if ( kbuf == NULL )
-        return -ENOMEM;
-
-    count &= ~1; /* even number of bytes */
-
-    if ( count == 0 )
-    {
-        rc = 0;
-        goto out;
-    }
-
-    if ( count > PAGE_SIZE )
-        count = PAGE_SIZE;
-
-    if ( copy_from_user(kbuf, buf, count) != 0 )
-    {
-        rc = -EFAULT;
-        goto out;
-    }
-
-    for ( i = 0; i < (count/2); i++ )
-        evtchn_clear_port(kbuf[i]);
-
-    rc = count;
-
- out:
-    free_page((unsigned long)kbuf);
-    return rc;
-}
-
-static int evtchn_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-    if ( cmd != EVTCHN_RESET )
-        return -EINVAL;
-
-    spin_lock_irq(&lock);
-    __evtchn_reset_buffer_ring();
-    spin_unlock_irq(&lock);   
-
-    return 0;
-}
-
-static unsigned int evtchn_poll(struct file *file, poll_table *wait)
-{
-    unsigned int mask = POLLOUT | POLLWRNORM;
-    poll_wait(file, &evtchn_wait, wait);
-    if ( ring_cons != ring_prod )
-        mask |= POLLIN | POLLRDNORM;
-    if ( ring_overflow )
-        mask = POLLERR;
-    return mask;
-}
-
-static int evtchn_fasync(int fd, struct file *filp, int on)
-{
-    return fasync_helper(fd, filp, on, &evtchn_async_queue);
-}
-
-static int evtchn_open(struct inode *inode, struct file *filp)
-{
-    u16 *_ring;
-
-    if ( test_and_set_bit(0, &evtchn_dev_inuse) )
-        return -EBUSY;
-
-    /* Allocate outside locked region so that we can use GFP_KERNEL. */
-    if ( (_ring = (u16 *)get_free_page(GFP_KERNEL)) == NULL )
-        return -ENOMEM;
-
-    spin_lock_irq(&lock);
-    ring = _ring;
-    __evtchn_reset_buffer_ring();
-    spin_unlock_irq(&lock);
-
-    MOD_INC_USE_COUNT;
-
-    return 0;
-}
-
-static int evtchn_release(struct inode *inode, struct file *filp)
-{
-    spin_lock_irq(&lock);
-    if ( ring != NULL )
-    {
-        free_page((unsigned long)ring);
-        ring = NULL;
-    }
-    spin_unlock_irq(&lock);
-
-    evtchn_dev_inuse = 0;
-
-    MOD_DEC_USE_COUNT;
-
-    return 0;
-}
-
-static struct file_operations evtchn_fops = {
-    owner:    THIS_MODULE,
-    read:     evtchn_read,
-    write:    evtchn_write,
-    ioctl:    evtchn_ioctl,
-    poll:     evtchn_poll,
-    fasync:   evtchn_fasync,
-    open:     evtchn_open,
-    release:  evtchn_release
-};
-
-static struct miscdevice evtchn_miscdev = {
-    minor:    EVTCHN_MINOR,
-    name:     "evtchn",
-    fops:     &evtchn_fops
-};
-
-static int __init init_module(void)
-{
-    devfs_handle_t symlink_handle;
-    int            err, pos;
-    char           link_dest[64];
-
-    /* (DEVFS) create '/dev/misc/evtchn'. */
-    err = misc_register(&evtchn_miscdev);
-    if ( err != 0 )
-    {
-        printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
-        return err;
-    }
-
-    /* (DEVFS) create directory '/dev/xen'. */
-    xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
-
-    /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
-    pos = devfs_generate_path(evtchn_miscdev.devfs_handle, 
-                              &link_dest[3], 
-                              sizeof(link_dest) - 3);
-    if ( pos >= 0 )
-        strncpy(&link_dest[pos], "../", 3);
-
-    /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
-    (void)devfs_mk_symlink(xen_dev_dir, 
-                           "evtchn", 
-                           DEVFS_FL_DEFAULT, 
-                           &link_dest[pos],
-                           &symlink_handle, 
-                           NULL);
-
-    /* (DEVFS) automatically destroy the symlink with its destination. */
-    devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
-
-    err = request_irq(HYPEREVENT_IRQ(_EVENT_EVTCHN),
-                      evtchn_interrupt, 0, "evtchn", NULL);
-    if ( err != 0 )
-    {
-        printk(KERN_ALERT "Could not allocate evtchn receive interrupt\n");
-        return err;
-    }
-
-    /* Kickstart servicing of notifications. */
-    evtchn_interrupt(0, NULL, NULL);
-
-    printk("Event-channel driver installed.\n");
-
-    return 0;
-}
-
-static void cleanup_module(void)
-{
-    free_irq(HYPEREVENT_IRQ(_EVENT_EVTCHN), NULL);
-    misc_deregister(&evtchn_miscdev);
-}
-
-module_init(init_module);
-module_exit(cleanup_module);
index b44a288a5bfcde1a987d806573a5a99c015a303c..2e4c1f4825d0b53b9fbc56351df3846ee3d36e45 100644 (file)
@@ -1,3 +1,3 @@
-O_TARGET := net.o
+O_TARGET := drv.o
 obj-y := network.o
 include $(TOPDIR)/Rules.make
index 512f6530a529c9181c5082d7243b1c5256e6a1ce..0a1bce2bfa6af3dbcc898743bd7961f4d398fa19 100644 (file)
@@ -415,7 +415,7 @@ static void network_interrupt(int irq, void *unused, struct pt_regs *ptregs)
 }
 
 
-int network_close(struct net_device *dev)
+static int network_close(struct net_device *dev)
 {
     struct net_private *np = dev->priv;
     netop_t netop;
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/Makefile b/xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/Makefile
new file mode 100644 (file)
index 0000000..304c2e7
--- /dev/null
@@ -0,0 +1,3 @@
+O_TARGET := drv.o
+obj-y := vnetif.o
+include $(TOPDIR)/Rules.make
diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/vnetif.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/vnetif/vnetif.c
new file mode 100644 (file)
index 0000000..465dd18
--- /dev/null
@@ -0,0 +1,552 @@
+/******************************************************************************
+ * vnetif.c
+ * 
+ * Virtual network driver for XenoLinux.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+
+#define RX_BUF_SIZE ((PAGE_SIZE/2)+1) /* Fool the slab allocator :-) */
+
+static void network_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
+static void network_tx_buf_gc(struct net_device *dev);
+static void network_alloc_rx_buffers(struct net_device *dev);
+static void cleanup_module(void);
+
+static struct list_head dev_list;
+
+struct net_private
+{
+    struct list_head list;
+    struct net_device *dev;
+
+    struct net_device_stats stats;
+    NET_RING_IDX rx_resp_cons, tx_resp_cons;
+    unsigned int net_ring_fixmap_idx, tx_full;
+    net_ring_t  *net_ring;
+    net_idx_t   *net_idx;
+    spinlock_t   tx_lock;
+    unsigned int idx; /* Domain-specific index of this VIF. */
+
+    unsigned int rx_bufs_to_notify;
+
+#define STATE_ACTIVE    0
+#define STATE_SUSPENDED 1
+#define STATE_CLOSED    2
+    unsigned int state;
+
+    /*
+     * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
+     * array is an index into a chain of free entries.
+     */
+    struct sk_buff *tx_skbs[TX_RING_SIZE+1];
+    struct sk_buff *rx_skbs[RX_RING_SIZE+1];
+};
+
+/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */
+#define ADD_ID_TO_FREELIST(_list, _id)             \
+    (_list)[(_id)] = (_list)[0];                   \
+    (_list)[0]     = (void *)(unsigned long)(_id);
+#define GET_ID_FROM_FREELIST(_list)                \
+ ({ unsigned long _id = (unsigned long)(_list)[0]; \
+    (_list)[0]  = (_list)[_id];                    \
+    (unsigned short)_id; })
+
+
+static void _dbg_network_int(struct net_device *dev)
+{
+    struct net_private *np = dev->priv;
+
+    if ( np->state == STATE_CLOSED )
+        return;
+    
+    printk(KERN_ALERT "net: tx_full=%d, tx_resp_cons=0x%08x,"
+           " tx_req_prod=0x%08x\nnet: tx_resp_prod=0x%08x,"
+           " tx_event=0x%08x, state=%d\n",
+           np->tx_full, np->tx_resp_cons, 
+           np->net_idx->tx_req_prod, np->net_idx->tx_resp_prod, 
+           np->net_idx->tx_event,
+           test_bit(__LINK_STATE_XOFF, &dev->state));
+    printk(KERN_ALERT "net: rx_resp_cons=0x%08x,"
+           " rx_req_prod=0x%08x\nnet: rx_resp_prod=0x%08x, rx_event=0x%08x\n",
+           np->rx_resp_cons, np->net_idx->rx_req_prod,
+           np->net_idx->rx_resp_prod, np->net_idx->rx_event);
+}
+
+
+static void dbg_network_int(int irq, void *unused, struct pt_regs *ptregs)
+{
+    struct list_head *ent;
+    struct net_private *np;
+    list_for_each ( ent, &dev_list )
+    {
+        np = list_entry(ent, struct net_private, list);
+        _dbg_network_int(np->dev);
+    }
+}
+
+
+static int network_open(struct net_device *dev)
+{
+    struct net_private *np = dev->priv;
+    netop_t netop;
+    int i, ret;
+
+    netop.cmd = NETOP_RESET_RINGS;
+    netop.vif = np->idx;
+    if ( (ret = HYPERVISOR_net_io_op(&netop)) != 0 )
+    {
+        printk(KERN_ALERT "Possible net trouble: couldn't reset ring idxs\n");
+        return ret;
+    }
+
+    netop.cmd = NETOP_GET_VIF_INFO;
+    netop.vif = np->idx;
+    if ( (ret = HYPERVISOR_net_io_op(&netop)) != 0 )
+    {
+        printk(KERN_ALERT "Couldn't get info for vif %d\n", np->idx);
+        return ret;
+    }
+
+    memcpy(dev->dev_addr, netop.u.get_vif_info.vmac, ETH_ALEN);
+
+    set_fixmap(FIX_NETRING0_BASE + np->net_ring_fixmap_idx, 
+               netop.u.get_vif_info.ring_mfn << PAGE_SHIFT);
+    np->net_ring = (net_ring_t *)fix_to_virt(
+        FIX_NETRING0_BASE + np->net_ring_fixmap_idx);
+    np->net_idx  = &HYPERVISOR_shared_info->net_idx[np->idx];
+
+    np->rx_bufs_to_notify = 0;
+    np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
+    memset(&np->stats, 0, sizeof(np->stats));
+    spin_lock_init(&np->tx_lock);
+    memset(np->net_ring, 0, sizeof(*np->net_ring));
+    memset(np->net_idx, 0, sizeof(*np->net_idx));
+
+    /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
+    for ( i = 0; i <= TX_RING_SIZE; i++ )
+        np->tx_skbs[i] = (void *)(i+1);
+    for ( i = 0; i <= RX_RING_SIZE; i++ )
+        np->rx_skbs[i] = (void *)(i+1);
+
+    wmb();
+    np->state = STATE_ACTIVE;
+
+    network_alloc_rx_buffers(dev);
+
+    netif_start_queue(dev);
+
+    MOD_INC_USE_COUNT;
+
+    return 0;
+}
+
+
+static void network_tx_buf_gc(struct net_device *dev)
+{
+    NET_RING_IDX i, prod;
+    unsigned short id;
+    struct net_private *np = dev->priv;
+    struct sk_buff *skb;
+    tx_entry_t *tx_ring = np->net_ring->tx_ring;
+
+    do {
+        prod = np->net_idx->tx_resp_prod;
+
+        for ( i = np->tx_resp_cons; i != prod; i++ )
+        {
+            id  = tx_ring[MASK_NET_TX_IDX(i)].resp.id;
+            skb = np->tx_skbs[id];
+            ADD_ID_TO_FREELIST(np->tx_skbs, id);
+            dev_kfree_skb_any(skb);
+        }
+        
+        np->tx_resp_cons = prod;
+        
+        /*
+         * Set a new event, then check for race with update of tx_cons. Note
+         * that it is essential to schedule a callback, no matter how few
+         * buffers are pending. Even if there is space in the transmit ring,
+         * higher layers may be blocked because too much data is outstanding:
+         * in such cases notification from Xen is likely to be the only kick
+         * that we'll get.
+         */
+        np->net_idx->tx_event = 
+            prod + ((np->net_idx->tx_req_prod - prod) >> 1) + 1;
+        mb();
+    }
+    while ( prod != np->net_idx->tx_resp_prod );
+
+    if ( np->tx_full && ((np->net_idx->tx_req_prod - prod) < TX_RING_SIZE) )
+    {
+        np->tx_full = 0;
+        if ( np->state == STATE_ACTIVE )
+            netif_wake_queue(dev);
+    }
+}
+
+
+static inline pte_t *get_ppte(void *addr)
+{
+    pgd_t *pgd; pmd_t *pmd; pte_t *pte;
+    pgd = pgd_offset_k(   (unsigned long)addr);
+    pmd = pmd_offset(pgd, (unsigned long)addr);
+    pte = pte_offset(pmd, (unsigned long)addr);
+    return pte;
+}
+
+
+static void network_alloc_rx_buffers(struct net_device *dev)
+{
+    unsigned short id;
+    struct net_private *np = dev->priv;
+    struct sk_buff *skb;
+    netop_t netop;
+    NET_RING_IDX i = np->net_idx->rx_req_prod;
+
+    if ( unlikely((i - np->rx_resp_cons) == RX_RING_SIZE) || 
+         unlikely(np->state != STATE_ACTIVE) )
+        return;
+
+    do {
+        skb = dev_alloc_skb(RX_BUF_SIZE);
+        if ( unlikely(skb == NULL) )
+            break;
+
+        skb->dev = dev;
+
+        if ( unlikely(((unsigned long)skb->head & (PAGE_SIZE-1)) != 0) )
+            panic("alloc_skb needs to provide us page-aligned buffers.");
+
+        id = GET_ID_FROM_FREELIST(np->rx_skbs);
+        np->rx_skbs[id] = skb;
+
+        np->net_ring->rx_ring[MASK_NET_RX_IDX(i)].req.id   = id;
+        np->net_ring->rx_ring[MASK_NET_RX_IDX(i)].req.addr = 
+            virt_to_machine(get_ppte(skb->head));
+
+        np->rx_bufs_to_notify++;
+    }
+    while ( (++i - np->rx_resp_cons) != RX_RING_SIZE );
+
+    /*
+     * We may have allocated buffers which have entries outstanding in the page
+     * update queue -- make sure we flush those first!
+     */
+    flush_page_update_queue();
+
+    np->net_idx->rx_req_prod = i;
+    np->net_idx->rx_event    = np->rx_resp_cons + 1;
+        
+    /* Batch Xen notifications. */
+    if ( np->rx_bufs_to_notify > (RX_RING_SIZE/4) )
+    {
+        netop.cmd = NETOP_PUSH_BUFFERS;
+        netop.vif = np->idx;
+        (void)HYPERVISOR_net_io_op(&netop);
+        np->rx_bufs_to_notify = 0;
+    }
+}
+
+
+static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    unsigned short id;
+    struct net_private *np = (struct net_private *)dev->priv;
+    tx_req_entry_t *tx;
+    netop_t netop;
+    NET_RING_IDX i;
+
+    if ( unlikely(np->tx_full) )
+    {
+        printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name);
+        netif_stop_queue(dev);
+        return -ENOBUFS;
+    }
+
+    if ( unlikely((((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >=
+                  PAGE_SIZE) )
+    {
+        struct sk_buff *new_skb = dev_alloc_skb(RX_BUF_SIZE);
+        if ( unlikely(new_skb == NULL) )
+            return 1;
+        skb_put(new_skb, skb->len);
+        memcpy(new_skb->data, skb->data, skb->len);
+        dev_kfree_skb(skb);
+        skb = new_skb;
+    }   
+    
+    spin_lock_irq(&np->tx_lock);
+
+    i = np->net_idx->tx_req_prod;
+
+    id = GET_ID_FROM_FREELIST(np->tx_skbs);
+    np->tx_skbs[id] = skb;
+
+    tx = &np->net_ring->tx_ring[MASK_NET_TX_IDX(i)].req;
+
+    tx->id   = id;
+    tx->addr = phys_to_machine(virt_to_phys(skb->data));
+    tx->size = skb->len;
+
+    wmb();
+    np->net_idx->tx_req_prod = i + 1;
+
+    network_tx_buf_gc(dev);
+
+    if ( (i - np->tx_resp_cons) == (TX_RING_SIZE - 1) )
+    {
+        np->tx_full = 1;
+        netif_stop_queue(dev);
+    }
+
+    spin_unlock_irq(&np->tx_lock);
+
+    np->stats.tx_bytes += skb->len;
+    np->stats.tx_packets++;
+
+    /* Only notify Xen if there are no outstanding responses. */
+    mb();
+    if ( np->net_idx->tx_resp_prod == i )
+    {
+        netop.cmd = NETOP_PUSH_BUFFERS;
+        netop.vif = np->idx;
+        (void)HYPERVISOR_net_io_op(&netop);
+    }
+
+    return 0;
+}
+
+
+static inline void _network_interrupt(struct net_device *dev)
+{
+    struct net_private *np = dev->priv;
+    unsigned long flags;
+    struct sk_buff *skb;
+    rx_resp_entry_t *rx;
+    NET_RING_IDX i;
+
+    if ( unlikely(np->state == STATE_CLOSED) )
+        return;
+    
+    spin_lock_irqsave(&np->tx_lock, flags);
+    network_tx_buf_gc(dev);
+    spin_unlock_irqrestore(&np->tx_lock, flags);
+
+ again:
+    for ( i = np->rx_resp_cons; i != np->net_idx->rx_resp_prod; i++ )
+    {
+        rx = &np->net_ring->rx_ring[MASK_NET_RX_IDX(i)].resp;
+
+        skb = np->rx_skbs[rx->id];
+        ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
+
+        if ( unlikely(rx->status != RING_STATUS_OK) )
+        {
+            /* Gate this error. We get a (valid) slew of them on suspend. */
+            if ( np->state == STATE_ACTIVE )
+                printk(KERN_ALERT "bad buffer on RX ring!(%d)\n", rx->status);
+            dev_kfree_skb_any(skb);
+            continue;
+        }
+
+        /*
+         * Set up shinfo -- from alloc_skb This was particularily nasty:  the
+         * shared info is hidden at the back of the data area (presumably so it
+         * can be shared), but on page flip it gets very spunked.
+         */
+        atomic_set(&(skb_shinfo(skb)->dataref), 1);
+        skb_shinfo(skb)->nr_frags = 0;
+        skb_shinfo(skb)->frag_list = NULL;
+                                
+        phys_to_machine_mapping[virt_to_phys(skb->head) >> PAGE_SHIFT] =
+            (*(unsigned long *)get_ppte(skb->head)) >> PAGE_SHIFT;
+
+        skb->data = skb->tail = skb->head + rx->offset;
+        skb_put(skb, rx->size);
+        skb->protocol = eth_type_trans(skb, dev);
+
+        np->stats.rx_packets++;
+
+        np->stats.rx_bytes += rx->size;
+        netif_rx(skb);
+        dev->last_rx = jiffies;
+    }
+
+    np->rx_resp_cons = i;
+
+    network_alloc_rx_buffers(dev);
+    
+    /* Deal with hypervisor racing our resetting of rx_event. */
+    mb();
+    if ( np->net_idx->rx_resp_prod != i )
+        goto again;
+}
+
+
+static void network_interrupt(int irq, void *unused, struct pt_regs *ptregs)
+{
+    struct list_head *ent;
+    struct net_private *np;
+    list_for_each ( ent, &dev_list )
+    {
+        np = list_entry(ent, struct net_private, list);
+        _network_interrupt(np->dev);
+    }
+}
+
+
+static int network_close(struct net_device *dev)
+{
+    struct net_private *np = dev->priv;
+    netop_t netop;
+
+    np->state = STATE_SUSPENDED;
+    wmb();
+
+    netif_stop_queue(np->dev);
+
+    netop.cmd = NETOP_FLUSH_BUFFERS;
+    netop.vif = np->idx;
+    (void)HYPERVISOR_net_io_op(&netop);
+
+    while ( (np->rx_resp_cons != np->net_idx->rx_req_prod) ||
+            (np->tx_resp_cons != np->net_idx->tx_req_prod) )
+    {
+        barrier();
+        current->state = TASK_INTERRUPTIBLE;
+        schedule_timeout(1);
+    }
+
+    wmb();
+    np->state = STATE_CLOSED;
+    wmb();
+
+    /* Now no longer safe to take interrupts for this device. */
+    clear_fixmap(FIX_NETRING0_BASE + np->net_ring_fixmap_idx);
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+}
+
+
+static struct net_device_stats *network_get_stats(struct net_device *dev)
+{
+    struct net_private *np = (struct net_private *)dev->priv;
+    return &np->stats;
+}
+
+
+static int __init init_module(void)
+{
+#if 0
+    int i, fixmap_idx=-1, err;
+    struct net_device *dev;
+    struct net_private *np;
+    netop_t netop;
+
+    INIT_LIST_HEAD(&dev_list);
+
+    err = request_irq(HYPEREVENT_IRQ(_EVENT_NET), network_interrupt, 
+                      SA_SAMPLE_RANDOM, "network", NULL);
+    if ( err )
+    {
+        printk(KERN_WARNING "Could not allocate network interrupt\n");
+        goto fail;
+    }
+    
+    err = request_irq(HYPEREVENT_IRQ(_EVENT_DEBUG), dbg_network_int, 
+                      SA_SHIRQ, "net_dbg", &dbg_network_int);
+    if ( err )
+        printk(KERN_WARNING "Non-fatal error -- no debug interrupt\n");
+
+    for ( i = 0; i < MAX_DOMAIN_VIFS; i++ )
+    {
+        /* If the VIF is invalid then the query hypercall will fail. */
+        netop.cmd = NETOP_GET_VIF_INFO;
+        netop.vif = i;
+        if ( HYPERVISOR_net_io_op(&netop) != 0 )
+            continue;
+
+        /* We actually only support up to 4 vifs right now. */
+        if ( ++fixmap_idx == 4 )
+            break;
+
+        dev = alloc_etherdev(sizeof(struct net_private));
+        if ( dev == NULL )
+        {
+            err = -ENOMEM;
+            goto fail;
+        }
+
+        np = dev->priv;
+        np->state               = STATE_CLOSED;
+        np->net_ring_fixmap_idx = fixmap_idx;
+        np->idx                 = i;
+
+        SET_MODULE_OWNER(dev);
+        dev->open            = network_open;
+        dev->hard_start_xmit = network_start_xmit;
+        dev->stop            = network_close;
+        dev->get_stats       = network_get_stats;
+
+        memcpy(dev->dev_addr, netop.u.get_vif_info.vmac, ETH_ALEN);
+
+        if ( (err = register_netdev(dev)) != 0 )
+        {
+            kfree(dev);
+            goto fail;
+        }
+
+        np->dev = dev;
+        list_add(&np->list, &dev_list);
+    }
+
+    return 0;
+
+ fail:
+    cleanup_module();
+    return err;
+#endif
+    return 0;
+}
+
+
+static void cleanup_module(void)
+{
+    struct net_private *np;
+    struct net_device *dev;
+
+    while ( !list_empty(&dev_list) )
+    {
+        np = list_entry(dev_list.next, struct net_private, list);
+        list_del(&np->list);
+        dev = np->dev;
+        unregister_netdev(dev);
+        kfree(dev);
+    }
+}
+
+
+module_init(init_module);
+module_exit(cleanup_module);